Merge "Modifying BLAST frame number to match BufferQueue"
diff --git a/aidl/binder/android/os/PersistableBundle.aidl b/aidl/binder/android/os/PersistableBundle.aidl
index 94e8607..493ecb4 100644
--- a/aidl/binder/android/os/PersistableBundle.aidl
+++ b/aidl/binder/android/os/PersistableBundle.aidl
@@ -17,4 +17,4 @@
 
 package android.os;
 
-parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
+@JavaOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a10baa6..e7b0d5d 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -273,7 +273,7 @@
     ps->startThreadPool();
     ps->giveThreadPoolName();
     sAppDataIsolationEnabled = android::base::GetBoolProperty(
-            kAppDataIsolationEnabledProperty, false);
+            kAppDataIsolationEnabledProperty, true);
     return android::OK;
 }
 
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 7f2f949..b574098 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -51,6 +51,7 @@
         RelativeParentChange        relative_parent         = 18;
         DetachChildrenChange        detach_children         = 19;
         ReparentChildrenChange      reparent_children       = 20;
+        BackgroundBlurRadiusChange  background_blur_radius  = 21;
         ShadowRadiusChange          shadow_radius           = 22;
     }
 }
@@ -73,6 +74,10 @@
     required float corner_radius = 1;
 }
 
+message BackgroundBlurRadiusChange {
+    required float background_blur_radius = 1;
+}
+
 message LayerChange {
     required uint32 layer = 1;
 }
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 675aad6..2b5667d 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -510,6 +510,14 @@
     t.setCornerRadius(mLayers[id], cc.corner_radius());
 }
 
+void Replayer::setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
+        layer_id id, const BackgroundBlurRadiusChange& cc) {
+    ALOGV("Layer %d: Setting Background Blur Radius -- backgroundBlurRadius=%d", id,
+        cc.background_blur_radius());
+
+    t.setBackgroundBlurRadius(mLayers[id], cc.background_blur_radius());
+}
+
 void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
         layer_id id, const MatrixChange& mc) {
     ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index b547834..95857e1 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -94,6 +94,8 @@
             layer_id id, const CropChange& cc);
     void setCornerRadius(SurfaceComposerClient::Transaction& t,
             layer_id id, const CornerRadiusChange& cc);
+    void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
+            layer_id id, const BackgroundBlurRadiusChange& cc);
     void setMatrix(SurfaceComposerClient::Transaction& t,
             layer_id id, const MatrixChange& mc);
     void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
index b598f68..082378d 100644
--- a/data/etc/android.hardware.telephony.cdma.xml
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -18,5 +18,4 @@
 <permissions>
     <feature name="android.hardware.telephony" />
     <feature name="android.hardware.telephony.cdma" />
-    <feature name="android.hardware.telephony.data" />
 </permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
index fe8a5cf..7927fa8 100644
--- a/data/etc/android.hardware.telephony.gsm.xml
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -18,5 +18,4 @@
 <permissions>
     <feature name="android.hardware.telephony" />
     <feature name="android.hardware.telephony.gsm" />
-    <feature name="android.hardware.telephony.data" />
 </permissions>
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 41718b2..5e03c6c 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -26,6 +26,7 @@
 #ifndef ANDROID_BITMAP_H
 #define ANDROID_BITMAP_H
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <jni.h>
 
@@ -78,6 +79,14 @@
     ANDROID_BITMAP_FLAGS_ALPHA_SHIFT    = 0,
 };
 
+enum {
+    /** If this bit is set in AndroidBitmapInfo.flags, the Bitmap uses the
+      * HARDWARE Config, and its AHardwareBuffer can be retrieved via
+      * AndroidBitmap_getHardwareBuffer.
+      */
+    ANDROID_BITMAP_FLAGS_IS_HARDWARE = 1 << 31,
+};
+
 /** Bitmap info, see AndroidBitmap_getInfo(). */
 typedef struct {
     /** The bitmap width in pixels. */
@@ -89,7 +98,9 @@
     /** The bitmap pixel format. See {@link AndroidBitmapFormat} */
     int32_t     format;
     /** Two bits are used to encode alpha. Use ANDROID_BITMAP_FLAGS_ALPHA_MASK
-      * and ANDROID_BITMAP_FLAGS_ALPHA_SHIFT to retrieve them. */
+      * and ANDROID_BITMAP_FLAGS_ALPHA_SHIFT to retrieve them. One bit is used
+      * to encode whether the Bitmap uses the HARDWARE Config. Use
+      * ANDROID_BITMAP_FLAGS_IS_HARDWARE to know.*/
     uint32_t    flags;
 } AndroidBitmapInfo;
 
@@ -133,6 +144,103 @@
  */
 int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
 
+#if __ANDROID_API__ >= 30
+
+// Note: these values match android.graphics.Bitmap#compressFormat.
+
+/**
+ *  Specifies the formats that can be compressed to with
+ *  {@link AndroidBitmap_compress}.
+ */
+enum AndroidBitmapCompressFormat {
+    /**
+     * Compress to the JPEG format. quality of 0 means
+     * compress for the smallest size. 100 means compress for max
+     * visual quality.
+     */
+    ANDROID_BITMAP_COMPRESS_FORMAT_JPEG = 0,
+    /**
+     * Compress to the PNG format. PNG is lossless, so quality is
+     * ignored.
+     */
+    ANDROID_BITMAP_COMPRESS_FORMAT_PNG = 1,
+    /**
+     * Compress to the WEBP lossy format. quality of 0 means
+     * compress for the smallest size. 100 means compress for max
+     * visual quality.
+     */
+    ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY = 3,
+    /**
+     * Compress to the WEBP lossless format. quality refers to how
+     * much effort to put into compression. A value of 0 means to
+     * compress quickly, resulting in a relatively large file size.
+     * 100 means to spend more time compressing, resulting in a
+     * smaller file.
+     */
+    ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS = 4,
+};
+
+/**
+ *  User-defined function for writing the output of compression.
+ *
+ *  @param userContext Pointer to user-defined data passed to
+ *         {@link AndroidBitmap_compress}.
+ *  @param data Compressed data of |size| bytes to write.
+ *  @param size Length in bytes of data to write.
+ *  @return Whether the operation succeeded.
+ */
+typedef bool (*AndroidBitmap_compress_write_fn)(void* userContext,
+                                                const void* data,
+                                                size_t size) __INTRODUCED_IN(30);
+
+/**
+ *  Compress |pixels| as described by |info|.
+ *
+ *  @param info Description of the pixels to compress.
+ *  @param dataspace {@link ADataSpace} describing the color space of the
+ *                   pixels.
+ *  @param pixels Pointer to pixels to compress.
+ *  @param format (@link AndroidBitmapCompressFormat} to compress to.
+ *  @param quality Hint to the compressor, 0-100. The value is interpreted
+ *                 differently depending on the
+ *                 {@link AndroidBitmapCompressFormat}.
+ *  @param userContext User-defined data which will be passed to the supplied
+ *                     {@link AndroidBitmap_compress_write_fn} each time it is
+ *                     called. May be null.
+ *  @parm fn Function that writes the compressed data. Will be called each time
+ *           the compressor has compressed more data that is ready to be
+ *           written. May be called more than once for each call to this method.
+ *           May not be null.
+ *  @return AndroidBitmap functions result code.
+ */
+int AndroidBitmap_compress(const AndroidBitmapInfo* info,
+                           int32_t dataspace,
+                           const void* pixels,
+                           int32_t format, int32_t quality,
+                           void* userContext,
+                           AndroidBitmap_compress_write_fn fn) __INTRODUCED_IN(30);
+
+struct AHardwareBuffer;
+
+/**
+ *  Retrieve the native object associated with a HARDWARE Bitmap.
+ *
+ *  Client must not modify it while a Bitmap is wrapping it.
+ *
+ *  @param bitmap Handle to an android.graphics.Bitmap.
+ *  @param outBuffer On success, is set to a pointer to the
+ *         AHardwareBuffer associated with bitmap. This acquires
+ *         a reference on the buffer, and the client must call
+ *         AHardwareBuffer_release when finished with it.
+ *  @return AndroidBitmap functions result code.
+ *          ANDROID_BITMAP_RESULT_BAD_PARAMETER if bitmap is not a
+ *          HARDWARE Bitmap.
+ */
+int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject bitmap,
+        AHardwareBuffer** outBuffer) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 50daaba..469b088 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -143,23 +143,39 @@
 int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*,
         int32_t format) __INTRODUCED_IN(30);
 
-/*
- * Choose the desired output format.
+/**
+ * Specify whether the output's pixels should be unpremultiplied.
  *
- * Must be one of:
- * {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}
- * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}
- * {@link ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL}
+ * By default, the decoder will premultiply the pixels, if they have alpha. Pass
+ * false to this method to leave them unpremultiplied. This has no effect on an
+ * opaque image.
  *
- * Note: An OPAQUE image may be set to any of them.
- *       A non-OPAQUE image may not be set to OPAQUE
- *
+ * @param required Pass true to leave the pixels unpremultiplied.
  * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
  *         - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION} if the conversion
  *           is not possible
  *         - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad parameters
  */
-int AImageDecoder_setAlphaFlags(AImageDecoder*, int alphaFlags) __INTRODUCED_IN(30);
+int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*, bool required) __INTRODUCED_IN(30);
+
+/**
+ * Choose the dataspace for the output.
+ *
+ * Not supported for {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
+ * an ADataSpace.
+ *
+ * @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
+ *                  specifies how to interpret the colors. By default,
+ *                  AImageDecoder will decode into the ADataSpace specified by
+ *                  {@link AImageDecoderHeaderInfo_getDataSpace}. If this
+ *                  parameter is set to a different ADataSpace, AImageDecoder
+ *                  will transform the output into the specified ADataSpace.
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ *         - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for a null
+ *           AImageDecoder or an integer that does not correspond to an
+ *           ADataSpace value.
+ */
+int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30);
 
 /**
  * Specify the output size for a decoded image.
@@ -182,6 +198,28 @@
  */
 int AImageDecoder_setTargetSize(AImageDecoder*, int width, int height) __INTRODUCED_IN(30);
 
+
+/**
+ * Compute the dimensions to use for a given sampleSize.
+ *
+ * Although AImageDecoder can scale to an arbitrary target size (see
+ * {@link AImageDecoder_setTargetSize}), some sizes may be more efficient than
+ * others. This computes the most efficient target size to use to reach a
+ * particular sampleSize.
+ *
+ * @param sampleSize A subsampling rate of the original image. Must be greater
+ *                   than or equal to 1. A sampleSize of 2 means to skip every
+ *                   other pixel/line, resulting in a width and height that are
+ *                   1/2 of the original dimensions, with 1/4 the number of
+ *                   pixels.
+ * @param width Out parameter for the width sampled by sampleSize, and rounded
+ *              direction that the decoder can do most efficiently.
+ * @param height Out parameter for the height sampled by sampleSize, and rounded
+ *               direction that the decoder can do most efficiently.
+ * @return ANDROID_IMAGE_DECODER result code.
+ */
+int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize,
+                                     int* width, int* height) __INTRODUCED_IN(30);
 /**
  * Specify how to crop the output after scaling (if any).
  *
@@ -264,6 +302,25 @@
         const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
 
 /**
+ * Report the dataspace the AImageDecoder will decode to by default.
+ * AImageDecoder will try to choose one that is sensible for the
+ * image and the system. Note that this may not exactly match the ICC
+ * profile (or other color information) stored in the encoded image.
+ *
+ * @return The {@link ADataSpace} most closely representing the way the colors
+ *         are encoded (or {@link ADATASPACE_UNKNOWN} if there is not an
+ *         approximate ADataSpace). This specifies how to interpret the colors
+ *         in the decoded image, unless {@link AImageDecoder_setDataSpace} is
+ *         called to decode to a different ADataSpace.
+ *
+ *         Note that ADataSpace only exposes a few values. This may return
+ *         ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no
+ *         corresponding ADataSpace.
+ */
+int32_t AImageDecoderHeaderInfo_getDataSpace(
+        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
  * Return the minimum stride that can be used, taking the specified
  * (or default) (possibly scaled) width, crop rect and
  * {@link AndroidBitmapFormat} into account.
diff --git a/include/android/input.h b/include/android/input.h
index f51cd79..dbfd61e 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -793,6 +793,8 @@
     AMOTION_EVENT_TOOL_TYPE_MOUSE = 3,
     /** eraser */
     AMOTION_EVENT_TOOL_TYPE_ERASER = 4,
+    /** palm */
+    AMOTION_EVENT_TOOL_TYPE_PALM = 5,
 };
 
 /**
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index ebd08b2..daaaa5a 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -90,8 +90,7 @@
 
 aidl_interface {
     name: "IBinderVendorDoubleLoadTest",
-    // TODO(b/119771576): only vendor is needed
-    vendor_available: true,
+    vendor: true,
     srcs: [
         "IBinderVendorDoubleLoadTest.aidl",
     ],
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index a8f7d92..b1943a4 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -14,6 +14,7 @@
         "-Wall",
         "-Wextra",
     ],
+    export_include_dirs: ["."],
 }
 
 cc_test {
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 4ee9f55..ee44cf5 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -85,6 +85,16 @@
     return policyN1 - policyN2;
 }
 
+static int bpf_obj_get_wronly(const char *pathname) {
+    union bpf_attr attr;
+
+    memset(&attr, 0, sizeof(attr));
+    attr.pathname = ptr_to_u64((void *)pathname);
+    attr.file_flags = BPF_F_WRONLY;
+
+    return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
 static bool initGlobals() {
     std::lock_guard<std::mutex> guard(gInitializedMutex);
     if (gInitialized) return true;
@@ -153,17 +163,17 @@
 bool startTrackingUidTimes() {
     if (!initGlobals()) return false;
 
-    unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
-    if (fd < 0) return false;
+    unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    if (cpuPolicyFd < 0) return false;
 
     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
         for (auto &cpu : gPolicyCpus[i]) {
-            if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+            if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false;
         }
     }
 
-    unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
-    if (fd2 < 0) return false;
+    unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    if (freqToIdxFd < 0) return false;
     freq_idx_key_t key;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         key.policy = i;
@@ -173,14 +183,41 @@
             // The uid_times map still uses 0-based indexes, and the sched_switch program handles
             // conversion between them, so this does not affect our map reading code.
             uint32_t idx = j + 1;
-            if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+            if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false;
         }
     }
 
+    unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    if (cpuLastUpdateFd < 0) return false;
+    std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
+    uint32_t zero = 0;
+    if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
+
+    unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    if (nrActiveFd < 0) return false;
+    if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
+
+    unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    if (policyNrActiveFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
+    }
+
+    unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    if (policyFreqIdxFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false;
+    }
+
     return attachTracepointProgram("sched", "sched_switch") &&
             attachTracepointProgram("power", "cpu_frequency");
 }
 
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
+    if (!gInitialized && !initGlobals()) return {};
+    return gPolicyFreqs;
+}
+
 // Retrieve the times in ns that uid spent running at each CPU frequency.
 // Return contains no value on error, otherwise it contains a vector of vectors using the format:
 // [[t0_0, t0_1, ...],
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index f620715..49469d8 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -26,6 +26,7 @@
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
 std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
     getUidsCpuFreqTimes();
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
 
 struct concurrent_time_t {
     std::vector<uint64_t> active;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index e82aad8..23d87fd 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -367,5 +367,16 @@
     ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
 }
 
+TEST(TimeInStateTest, GetCpuFreqs) {
+    auto freqs = getCpuFreqs();
+    ASSERT_TRUE(freqs.has_value());
+
+    auto times = getUidCpuFreqTimes(0);
+    ASSERT_TRUE(times.has_value());
+
+    ASSERT_EQ(freqs->size(), times->size());
+    for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index ca0d4b5..42c6e15 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -30,6 +30,8 @@
 #include <aidl/android/hardware/graphics/common/XyColor.h>
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
 
+namespace android {
+
 /**
  * Define equality operators for Stable AIDL types.
  */
@@ -210,8 +212,6 @@
     return !(lhs == rhs);
 }
 
-namespace android {
-
 namespace gralloc4 {
 
 #define GRALLOC4_STANDARD_METADATA_TYPE "android.hardware.graphics.common.StandardMetadataType"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5959340..55a892e 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -69,9 +69,6 @@
         "SurfaceComposerClient.cpp",
         "SyncFeatures.cpp",
         "view/Surface.cpp",
-        "surfacetexture/SurfaceTexture.cpp",
-        "surfacetexture/ImageConsumer.cpp",
-        "surfacetexture/EGLConsumer.cpp",
     ],
 
     shared_libs: [
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f88ddf1..9674e54 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -109,7 +109,7 @@
 
 void BLASTBufferQueue::processNextBufferLocked() {
     ATRACE_CALL();
-    if (mNumFrameAvailable == 0) {
+    if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) {
         return;
     }
 
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
index b5cdeb2..0ddb87e 100644
--- a/libs/gui/BufferHubConsumer.cpp
+++ b/libs/gui/BufferHubConsumer.cpp
@@ -147,6 +147,16 @@
     return INVALID_OPERATION;
 }
 
+status_t BufferHubConsumer::setFrameRate(float /*frameRate*/) {
+    ALOGE("BufferHubConsumer::setFrameRate: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::getFrameRate(float* /*frameRate*/) const {
+    ALOGE("BufferHubConsumer::getFrameRate: not implemented.");
+    return INVALID_OPERATION;
+}
+
 status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
     ALOGE("BufferHubConsumer::dumpState: not implemented.");
     return INVALID_OPERATION;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 6418e8c..9b74fef 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -775,6 +775,18 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueConsumer::setFrameRate(float frameRate) {
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    mCore->mFrameRate = frameRate;
+    return NO_ERROR;
+}
+
+status_t BufferQueueConsumer::getFrameRate(float* frameRate) const {
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    *frameRate = mCore->mFrameRate;
+    return NO_ERROR;
+}
+
 status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
     struct passwd* pwd = getpwnam("shell");
     uid_t shellUid = pwd ? pwd->pw_uid : 0;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index e6df757..6b11a54 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1670,4 +1670,14 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::setFrameRate(float frameRate) {
+    ATRACE_CALL();
+    BQ_LOGV("setFrameRate: %.0f", frameRate);
+
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+
+    mCore->mFrameRate = frameRate;
+    return NO_ERROR;
+}
+
 } // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 9f91d9d..515f45c 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -363,6 +363,24 @@
     return OK;
 }
 
+status_t ConsumerBase::setFrameRate(float frameRate) {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setFrameRate: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setFrameRate(frameRate);
+}
+
+status_t ConsumerBase::getFrameRate(float* frameRate) {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("getFrameRate: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->getFrameRate(frameRate);
+}
+
 void ConsumerBase::dumpState(String8& result) const {
     dumpState(result, "");
 }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index c705d39..2521a7c 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -51,6 +51,8 @@
     GET_SIDEBAND_STREAM,
     GET_OCCUPANCY_HISTORY,
     DISCARD_FREE_BUFFERS,
+    SET_FRAME_RATE,
+    GET_FRAME_RATE,
     DUMP_STATE,
     LAST = DUMP_STATE,
 };
@@ -163,6 +165,16 @@
                 Tag::DISCARD_FREE_BUFFERS);
     }
 
+    status_t setFrameRate(float frameRate) override {
+        using Signature = decltype(&IGraphicBufferConsumer::setFrameRate);
+        return callRemote<Signature>(Tag::SET_FRAME_RATE, frameRate);
+    }
+
+    status_t getFrameRate(float* frameRate) const override {
+        using Signature = decltype(&IGraphicBufferConsumer::getFrameRate);
+        return callRemote<Signature>(Tag::GET_FRAME_RATE, frameRate);
+    }
+
     status_t dumpState(const String8& prefix, String8* outResult) const override {
         using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
         return callRemote<Signature>(Tag::DUMP_STATE, prefix, outResult);
@@ -220,6 +232,10 @@
             return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory);
         case Tag::DISCARD_FREE_BUFFERS:
             return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers);
+        case Tag::SET_FRAME_RATE:
+            return callLocal(data, reply, &IGraphicBufferConsumer::setFrameRate);
+        case Tag::GET_FRAME_RATE:
+            return callLocal(data, reply, &IGraphicBufferConsumer::getFrameRate);
         case Tag::DUMP_STATE: {
             using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
             return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0009a57..75876f2 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -74,6 +74,7 @@
     GET_CONSUMER_USAGE,
     SET_LEGACY_BUFFER_DROP,
     SET_AUTO_PREROTATION,
+    SET_FRAME_RATE,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -559,6 +560,14 @@
         }
         return result;
     }
+
+    virtual status_t setFrameRate(float frameRate) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeFloat(frameRate);
+        status_t result = remote()->transact(SET_FRAME_RATE, data, &reply, IBinder::FLAG_ONEWAY);
+        return result;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -691,6 +700,8 @@
     status_t setAutoPrerotation(bool autoPrerotation) override {
         return mBase->setAutoPrerotation(autoPrerotation);
     }
+
+    status_t setFrameRate(float frameRate) override { return mBase->setFrameRate(frameRate); }
 };
 
 IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
@@ -710,6 +721,12 @@
     return INVALID_OPERATION;
 }
 
+status_t IGraphicBufferProducer::setFrameRate(float frameRate) {
+    // No-op for IGBP other than BufferQueue.
+    (void)frameRate;
+    return INVALID_OPERATION;
+}
+
 status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
     status_t res = OK;
     res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1079,6 +1096,13 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case SET_FRAME_RATE: {
+            CHECK_INTERFACE(IGraphicBuffer, data, reply);
+            float frameRate = data.readFloat();
+            status_t result = setFrameRate(frameRate);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index d34fe3b..073543c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -397,32 +397,6 @@
         return reply.readInt32();
     }
 
-    virtual status_t setActiveConfig(const sp<IBinder>& display, int id)
-    {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveConfig failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = data.writeInt32(id);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveConfig failed to writeInt32: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveConfig failed to transact: %d", result);
-            return result;
-        }
-        return reply.readInt32();
-    }
-
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
             Vector<ColorMode>* outColorModes) {
         Parcel data, reply;
@@ -1357,14 +1331,6 @@
             reply->writeInt32(id);
             return NO_ERROR;
         }
-        case SET_ACTIVE_CONFIG: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = data.readStrongBinder();
-            int id = data.readInt32();
-            status_t result = setActiveConfig(display, id);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
         case GET_DISPLAY_COLOR_MODES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             Vector<ColorMode> colorModes;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index a7c4f46..5547efc 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -86,6 +86,7 @@
     memcpy(output.writeInplace(16 * sizeof(float)),
            colorTransform.asArray(), 16 * sizeof(float));
     output.writeFloat(cornerRadius);
+    output.writeUint32(backgroundBlurRadius);
     output.writeStrongBinder(cachedBuffer.token.promote());
     output.writeUint64(cachedBuffer.id);
     output.writeParcelable(metadata);
@@ -110,6 +111,8 @@
         }
     }
     output.writeFloat(shadowRadius);
+    output.writeInt32(frameRateSelectionPriority);
+    output.writeFloat(frameRate);
     return NO_ERROR;
 }
 
@@ -171,6 +174,7 @@
 
     colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
     cornerRadius = input.readFloat();
+    backgroundBlurRadius = input.readUint32();
     cachedBuffer.token = input.readStrongBinder();
     cachedBuffer.id = input.readUint64();
     input.readParcelable(&metadata);
@@ -188,6 +192,8 @@
         listeners.emplace_back(listener, callbackIds);
     }
     shadowRadius = input.readFloat();
+    frameRateSelectionPriority = input.readInt32();
+    frameRate = input.readFloat();
     return NO_ERROR;
 }
 
@@ -303,6 +309,10 @@
         what |= eCornerRadiusChanged;
         cornerRadius = other.cornerRadius;
     }
+    if (other.what & eBackgroundBlurRadiusChanged) {
+        what |= eBackgroundBlurRadiusChanged;
+        backgroundBlurRadius = other.backgroundBlurRadius;
+    }
     if (other.what & eDeferTransaction_legacy) {
         what |= eDeferTransaction_legacy;
         barrierHandle_legacy = other.barrierHandle_legacy;
@@ -406,12 +416,18 @@
         what |= eMetadataChanged;
         metadata.merge(other.metadata);
     }
-
     if (other.what & eShadowRadiusChanged) {
         what |= eShadowRadiusChanged;
         shadowRadius = other.shadowRadius;
     }
-
+    if (other.what & eFrameRateSelectionPriority) {
+        what |= eFrameRateSelectionPriority;
+        frameRateSelectionPriority = other.frameRateSelectionPriority;
+    }
+    if (other.what & eFrameRateChanged) {
+        what |= eFrameRateChanged;
+        frameRate = other.frameRate;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 274153c..c13401d 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,3 +1,6 @@
+adyabr@google.com
+akrulec@google.com
+alecmouri@google.com
 jessehall@google.com
 jwcai@google.com
 lpy@google.com
@@ -6,3 +9,4 @@
 racarr@google.com
 steventhomas@google.com
 stoza@google.com
+vhau@google.com
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e490d6d..d5cf11d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1093,6 +1093,9 @@
     case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION:
         res = dispatchGetLastQueueDuration(args);
         break;
+    case NATIVE_WINDOW_SET_FRAME_RATE:
+        res = dispatchSetFrameRate(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1321,6 +1324,11 @@
     return NO_ERROR;
 }
 
+int Surface::dispatchSetFrameRate(va_list args) {
+    float frameRate = static_cast<float>(va_arg(args, double));
+    return setFrameRate(frameRate);
+}
+
 bool Surface::transformToDisplayInverse() {
     return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -2064,4 +2072,11 @@
     mSurfaceListener->onBuffersDiscarded(discardedBufs);
 }
 
+status_t Surface::setFrameRate(float frameRate) {
+    ATRACE_CALL();
+    ALOGV("Surface::setTargetFrameRate");
+    Mutex::Autolock lock(mMutex);
+    return mGraphicBufferProducer->setFrameRate(frameRate);
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5e259e2..63dc333 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -918,6 +918,18 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius(
+        const sp<SurfaceControl>& sc, int backgroundBlurRadius) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eBackgroundBlurRadiusChanged;
+    s->backgroundBlurRadius = backgroundBlurRadius;
+    return *this;
+}
+
 SurfaceComposerClient::Transaction&
 SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
                                                                  const sp<IBinder>& handle,
@@ -1192,6 +1204,22 @@
 }
 
 SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<SurfaceControl>& sc,
+                                                                  int32_t priority) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eFrameRateSelectionPriority;
+    s->frameRateSelectionPriority = priority;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction&
 SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
         TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
     auto listener = TransactionCompletedListener::getInstance();
@@ -1360,6 +1388,18 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
+        const sp<SurfaceControl>& sc, float frameRate) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eFrameRateChanged;
+    s->frameRate = frameRate;
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1611,10 +1651,6 @@
     return ComposerService::getComposerService()->getActiveConfig(display);
 }
 
-status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int id) {
-    return ComposerService::getComposerService()->setActiveConfig(display, id);
-}
-
 status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                              int32_t defaultConfig,
                                                              float minRefreshRate,
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
index d380770..d756203 100644
--- a/libs/gui/include/gui/BufferHubConsumer.h
+++ b/libs/gui/include/gui/BufferHubConsumer.h
@@ -93,6 +93,12 @@
     // See |IGraphicBufferConsumer::discardFreeBuffers|
     status_t discardFreeBuffers() override;
 
+    // See |IGraphicBufferConsumer::setFrameRate|
+    status_t setFrameRate(float frameRate) override;
+
+    // See |IGraphicBufferConsumer::getFrameRate|
+    status_t getFrameRate(float* frameRate) const override;
+
     // See |IGraphicBufferConsumer::dumpState|
     status_t dumpState(const String8& prefix, String8* outResult) const override;
 
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index 7db69ec..e9f0449 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -149,6 +149,12 @@
     // See IGraphicBufferConsumer::discardFreeBuffers
     virtual status_t discardFreeBuffers() override;
 
+    // See IGraphicBufferConsumer::setFrameRate.
+    virtual status_t setFrameRate(float frameRate) override;
+
+    // See IGraphicBufferConsumer::getFrameRate.
+    virtual status_t getFrameRate(float* frameRate) const override;
+
     // dump our state in a String
     status_t dumpState(const String8& prefix, String8* outResult) const override;
 
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 557c28b..05c2074 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -354,6 +354,9 @@
     // mTransformHintInUse is to cache the mTransformHint used by the producer.
     uint32_t mTransformHintInUse;
 
+    // The frame rate the app intends to run at.
+    float mFrameRate;
+
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 9ad92a6..2dec663 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -193,6 +193,9 @@
     // See IGraphicBufferProducer::setAutoPrerotation
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
+    // See IGraphicBufferProducer::setFrameRate
+    virtual status_t setFrameRate(float frameRate) override;
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 8ff0cd0..cfed9aa 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -111,6 +111,12 @@
     // See IGraphicBufferConsumer::discardFreeBuffers
     status_t discardFreeBuffers();
 
+    // See IGraphicBufferConsumer::setFrameRate
+    status_t setFrameRate(float frameRate);
+
+    // See IGraphicBufferConsumer::getFrameRate
+    status_t getFrameRate(float* frameRate);
+
 private:
     ConsumerBase(const ConsumerBase&);
     void operator=(const ConsumerBase&);
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 9fb7580..54f77b4 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -271,6 +271,16 @@
     // call to free up any of its locally cached buffers.
     virtual status_t discardFreeBuffers() = 0;
 
+    // Set the frame rate the producer will run at.
+    //
+    // Return of a value other than NO_ERROR means an unknown error has occurred.
+    virtual status_t setFrameRate(float frameRate) = 0;
+
+    // Get the frame rate the producer will run at.
+    //
+    // Return of a value other than NO_ERROR means an unknown error has occurred.
+    virtual status_t getFrameRate(float* frameRate) const = 0;
+
     // dump state into a string
     virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0;
 
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 25ce1ca..680d64e 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -637,6 +637,9 @@
     // the width and height used for dequeueBuffer will be additionally swapped.
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
+    // Sets the apps intended frame rate.
+    virtual status_t setFrameRate(float frameRate);
+
     // Static method exports any IGraphicBufferProducer object to a parcel. It
     // handles null producer as well.
     static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 9804c92..46c9f3a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -176,10 +176,6 @@
      * currently active */
     virtual int getActiveConfig(const sp<IBinder>& display) = 0;
 
-    /* specifies which configuration (of those returned by getDisplayInfo)
-     * should be used */
-    virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0;
-
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
             Vector<ui::ColorMode>* outColorModes) = 0;
     virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
@@ -507,7 +503,6 @@
         GET_SUPPORTED_FRAME_TIMESTAMPS,
         GET_DISPLAY_CONFIGS,
         GET_ACTIVE_CONFIG,
-        SET_ACTIVE_CONFIG,
         CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
         CAPTURE_SCREEN,
         CAPTURE_LAYERS,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index fb18639..c256a09 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -99,6 +99,9 @@
         eBackgroundColorChanged = 0x4'00000000,
         eMetadataChanged = 0x8'00000000,
         eColorSpaceAgnosticChanged = 0x10'00000000,
+        eFrameRateSelectionPriority = 0x20'00000000,
+        eFrameRateChanged = 0x40'00000000,
+        eBackgroundBlurRadiusChanged = 0x80'00000000,
     };
 
     layer_state_t()
@@ -115,6 +118,7 @@
             reserved(0),
             crop_legacy(Rect::INVALID_RECT),
             cornerRadius(0.0f),
+            backgroundBlurRadius(0),
             frameNumber_legacy(0),
             overrideScalingMode(-1),
             transform(0),
@@ -128,7 +132,9 @@
             bgColorAlpha(0),
             bgColorDataspace(ui::Dataspace::UNKNOWN),
             colorSpaceAgnostic(false),
-            shadowRadius(0.0f) {
+            shadowRadius(0.0f),
+            frameRateSelectionPriority(-1),
+            frameRate(0.0f) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
         hdrMetadata.validTypes = 0;
@@ -159,6 +165,7 @@
     matrix22_t matrix;
     Rect crop_legacy;
     float cornerRadius;
+    uint32_t backgroundBlurRadius;
     sp<IBinder> barrierHandle_legacy;
     sp<IBinder> reparentHandle;
     uint64_t frameNumber_legacy;
@@ -209,6 +216,11 @@
 
     // Draws a shadow around the surface.
     float shadowRadius;
+
+    // Priority of the layer assigned by Window Manager.
+    int32_t frameRateSelectionPriority;
+
+    float frameRate;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index e582509..86cc61f 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -179,6 +179,9 @@
     status_t getUniqueId(uint64_t* outId) const;
     status_t getConsumerUsage(uint64_t* outUsage) const;
 
+    // See IGraphicBufferProducer::setFrameRate
+    status_t setFrameRate(float frameRate);
+
 protected:
     virtual ~Surface();
 
@@ -248,6 +251,7 @@
     int dispatchSetDequeueTimeout(va_list args);
     int dispatchGetLastDequeueDuration(va_list args);
     int dispatchGetLastQueueDuration(va_list args);
+    int dispatchSetFrameRate(va_list args);
     bool transformToDisplayInverse();
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 44f29ea..08e6a5a 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -114,10 +114,6 @@
     // returned by getDisplayInfo)
     static int getActiveConfig(const sp<IBinder>& display);
 
-    // Set a new active configuration using an index relative to the list
-    // returned by getDisplayInfo
-    static status_t setActiveConfig(const sp<IBinder>& display, int id);
-
     // Sets the refresh rate boundaries for display configuration.
     // For all other parameters, default configuration is used. The index for the default is
     // corresponting to the configs returned from getDisplayConfigs().
@@ -435,6 +431,8 @@
                 float dsdx, float dtdx, float dtdy, float dsdy);
         Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
         Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
+        Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
+                                             int backgroundBlurRadius);
         Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
         Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
         // Defers applying any changes made in this transaction until the Layer
@@ -483,6 +481,9 @@
         Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
         Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
 
+        // Sets information about the priority of the frame.
+        Transaction& setFrameRateSelectionPriority(const sp<SurfaceControl>& sc, int32_t priority);
+
         Transaction& addTransactionCompletedCallback(
                 TransactionCompletedCallbackTakesContext callback, void* callbackContext);
 
@@ -517,6 +518,8 @@
                 const Rect& source, const Rect& dst, int transform);
         Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius);
 
+        Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
index 98f24c2..e940cf3 100644
--- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h
+++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
@@ -49,6 +49,8 @@
     MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
     MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
     MOCK_METHOD0(discardFreeBuffers, status_t());
+    MOCK_METHOD1(setFrameRate, status_t(float));
+    MOCK_CONST_METHOD1(getFrameRate, status_t(float*));
     MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
 };
 
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 8d36ba7..04749e6 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -112,22 +112,31 @@
         if (consumed != OK) {
             return nullptr;
         }
-        mInputConsumer->sendFinishedSignal(seqId, true);
+        status_t status = mInputConsumer->sendFinishedSignal(seqId, true);
+        EXPECT_EQ(OK, status) << "Could not send finished signal";
         return ev;
     }
 
+    void assertFocusChange(bool hasFocus) {
+        InputEvent *ev = consumeEvent();
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(AINPUT_EVENT_TYPE_FOCUS, ev->getType());
+        FocusEvent *focusEvent = static_cast<FocusEvent *>(ev);
+        EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
+    }
+
     void expectTap(int x, int y) {
         InputEvent* ev = consumeEvent();
-        EXPECT_TRUE(ev != nullptr);
-        EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
         MotionEvent* mev = static_cast<MotionEvent*>(ev);
         EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
         EXPECT_EQ(x, mev->getX(0));
         EXPECT_EQ(y, mev->getY(0));
 
         ev = consumeEvent();
-        EXPECT_TRUE(ev != nullptr);
-        EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
         mev = static_cast<MotionEvent*>(ev);
         EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
     }
@@ -212,7 +221,7 @@
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
         const auto display = mComposerClient->getInternalDisplayToken();
-        ASSERT_FALSE(display == nullptr);
+        ASSERT_NE(display, nullptr);
 
         DisplayInfo info;
         ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
@@ -259,18 +268,28 @@
 TEST_F(InputSurfacesTest, can_receive_input) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->showAt(100, 100);
+    surface->assertFocusChange(true);
 
     injectTap(101, 101);
 
-    EXPECT_TRUE(surface->consumeEvent() != nullptr);
+    EXPECT_NE(surface->consumeEvent(), nullptr);
 }
 
+/**
+ * Set up two surfaces side-by-side. Tap each surface.
+ * Next, swap the positions of the two surfaces. Inject tap into the two
+ * original locations. Ensure that the tap is received by the surfaces in the
+ * reverse order.
+ */
 TEST_F(InputSurfacesTest, input_respects_positioning) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->showAt(100, 100);
+    surface->assertFocusChange(true);
 
     std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
     surface2->showAt(200, 200);
+    surface->assertFocusChange(false);
+    surface2->assertFocusChange(true);
 
     injectTap(201, 201);
     surface2->expectTap(1, 1);
@@ -297,11 +316,16 @@
     std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
 
     surface->showAt(10, 10);
+    surface->assertFocusChange(true);
     surface2->showAt(10, 10);
+    surface->assertFocusChange(false);
+    surface2->assertFocusChange(true);
 
     surface->doTransaction([](auto &t, auto &sc) {
          t.setLayer(sc, LAYER_BASE + 1);
     });
+    surface2->assertFocusChange(false);
+    surface->assertFocusChange(true);
 
     injectTap(11, 11);
     surface->expectTap(1, 1);
@@ -309,6 +333,8 @@
     surface2->doTransaction([](auto &t, auto &sc) {
          t.setLayer(sc, LAYER_BASE + 1);
     });
+    surface2->assertFocusChange(true);
+    surface->assertFocusChange(false);
 
     injectTap(11, 11);
     surface2->expectTap(1, 1);
@@ -316,6 +342,8 @@
     surface2->doTransaction([](auto &t, auto &sc) {
          t.hide(sc);
     });
+    surface2->assertFocusChange(false);
+    surface->assertFocusChange(true);
 
     injectTap(11, 11);
     surface->expectTap(1, 1);
@@ -328,9 +356,12 @@
     std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
     bgSurface->showAt(100, 100);
+    bgSurface->assertFocusChange(true);
 
     fgSurface->mInputInfo.surfaceInset = 5;
     fgSurface->showAt(100, 100);
+    fgSurface->assertFocusChange(true);
+    bgSurface->assertFocusChange(false);
 
     injectTap(106, 106);
     fgSurface->expectTap(1, 1);
@@ -344,9 +375,12 @@
     std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
     parentSurface->showAt(100, 100);
+    parentSurface->assertFocusChange(true);
 
     childSurface->mInputInfo.surfaceInset = 10;
     childSurface->showAt(100, 100);
+    childSurface->assertFocusChange(true);
+    parentSurface->assertFocusChange(false);
 
     childSurface->doTransaction([&](auto &t, auto &sc) {
         t.setPosition(sc, -5, -5);
@@ -365,9 +399,12 @@
     std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
     bgSurface->showAt(100, 100);
+    bgSurface->assertFocusChange(true);
 
     fgSurface->mInputInfo.surfaceInset = 5;
     fgSurface->showAt(100, 100);
+    bgSurface->assertFocusChange(false);
+    fgSurface->assertFocusChange(true);
 
     fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 4.0); });
 
@@ -384,6 +421,7 @@
     // In case we pass the very big inset without any checking.
     fgSurface->mInputInfo.surfaceInset = INT32_MAX;
     fgSurface->showAt(100, 100);
+    fgSurface->assertFocusChange(true);
 
     fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
 
@@ -400,6 +438,7 @@
         t.setTransparentRegionHint(sc, transparentRegion);
     });
     surface->showAt(100, 100);
+    surface->assertFocusChange(true);
     injectTap(101, 101);
     surface->expectTap(1, 1);
 }
@@ -414,7 +453,10 @@
             InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
 
     bgSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(true);
     bufferSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(false);
+    bufferSurface->assertFocusChange(true);
 
     injectTap(11, 11);
     bufferSurface->expectTap(1, 1);
@@ -431,7 +473,10 @@
     postBuffer(bufferSurface->mSurfaceControl);
 
     bgSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(true);
     bufferSurface->showAt(10, 10);
+    bufferSurface->assertFocusChange(true);
+    bgSurface->assertFocusChange(false);
 
     injectTap(11, 11);
     bufferSurface->expectTap(1, 1);
@@ -447,7 +492,10 @@
     std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
 
     bgSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(true);
     fgSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(false);
+    fgSurface->assertFocusChange(true);
 
     injectTap(11, 11);
     fgSurface->expectTap(1, 1);
@@ -464,12 +512,17 @@
             InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
 
     bgSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(true);
     containerSurface->showAt(10, 10);
+    bgSurface->assertFocusChange(false);
+    containerSurface->assertFocusChange(true);
 
     injectTap(11, 11);
     containerSurface->expectTap(1, 1);
 
     containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
+    containerSurface->assertFocusChange(false);
+    bgSurface->assertFocusChange(true);
 
     injectTap(11, 11);
     bgSurface->expectTap(1, 1);
@@ -478,6 +531,7 @@
 TEST_F(InputSurfacesTest, input_respects_outscreen) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->showAt(-1, -1);
+    surface->assertFocusChange(true);
 
     injectTap(0, 0);
     surface->expectTap(1, 1);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index f9540b2..25c032f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -723,10 +723,6 @@
     status_t getDisplayStats(const sp<IBinder>& /*display*/,
             DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
     int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
-    status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
-            override {
-        return NO_ERROR;
-    }
     status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
             Vector<ColorMode>* /*outColorModes*/) override {
         return NO_ERROR;
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 6566538..1e25049 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -129,6 +129,8 @@
 }
 } // namespace
 
+namespace android {
+
 int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
     const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
     const size_t size = ids.size();
@@ -298,3 +300,5 @@
 
     return reinterpret_cast<DisplayConfigImpl*>(config)->appOffset;
 }
+
+} // namespace android
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index d37b9a1..c956578 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -40,9 +40,15 @@
         "-Wno-unused-function",
     ],
 
+    version_script: "libnativedisplay.map.txt",
+
     srcs: [
         "AChoreographer.cpp",
         "ADisplay.cpp",
+        "surfacetexture/surface_texture.cpp",
+        "surfacetexture/SurfaceTexture.cpp",
+        "surfacetexture/ImageConsumer.cpp",
+        "surfacetexture/EGLConsumer.cpp",
     ],
 
     shared_libs: [
@@ -51,6 +57,10 @@
         "libnativewindow",
         "libui",
         "libutils",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libnativehelper",
     ],
 
     header_libs: [
diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h
index 9be401e..a7eaf87 100644
--- a/libs/nativedisplay/include/apex/display.h
+++ b/libs/nativedisplay/include/apex/display.h
@@ -20,7 +20,12 @@
 #include <android/hardware_buffer.h>
 #include <inttypes.h>
 
-__BEGIN_DECLS
+// TODO: the intention of these apis is to be stable - hence they are defined in
+// an apex directory. But because they don't yet need to be stable, hold off on
+// making them stable until a Mainline module needs them.
+// __BEGIN_DECLS
+
+namespace android {
 
 /**
  * Opaque handle for a native display
@@ -130,4 +135,5 @@
  */
 int64_t ADisplayConfig_getAppVsyncOffsetNanos(ADisplayConfig* config);
 
-__END_DECLS
+} // namespace android
+// __END_DECLS
diff --git a/libs/gui/include/gui/surfacetexture/EGLConsumer.h b/libs/nativedisplay/include/surfacetexture/EGLConsumer.h
similarity index 100%
rename from libs/gui/include/gui/surfacetexture/EGLConsumer.h
rename to libs/nativedisplay/include/surfacetexture/EGLConsumer.h
diff --git a/libs/gui/include/gui/surfacetexture/ImageConsumer.h b/libs/nativedisplay/include/surfacetexture/ImageConsumer.h
similarity index 100%
rename from libs/gui/include/gui/surfacetexture/ImageConsumer.h
rename to libs/nativedisplay/include/surfacetexture/ImageConsumer.h
diff --git a/libs/gui/include/gui/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
similarity index 100%
rename from libs/gui/include/gui/surfacetexture/SurfaceTexture.h
rename to libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
diff --git a/libs/gui/include/gui/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
similarity index 85%
rename from libs/gui/include/gui/surfacetexture/surface_texture_platform.h
rename to libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index 72f98ad..6a94a77 100644
--- a/libs/gui/include/gui/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -22,17 +22,11 @@
 
 #include <system/graphics.h>
 
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
-
 // This file provides a facade API on top of SurfaceTexture, which avoids using
 // C++ types. This is still a C++ unstable API though. Ideally features here
 // will be exposed via public NDK API and this file will be deleted.
 
-struct ASurfaceTexture {
-    android::sp<android::SurfaceTexture> consumer;
-    android::sp<android::IGraphicBufferProducer> producer;
-};
+struct ASurfaceTexture;
 
 namespace android {
 
@@ -79,13 +73,6 @@
                                                ASurfaceTexture_fenceWait fenceWait,
                                                void* fencePassThroughHandle);
 
-/**
- * ASurfaceTexture_create creates an ASurfaceTexture, which is
- * a simple struct containing a SurfaceTexture and an IGraphicBufferProducer.
- */
-ASurfaceTexture* ASurfaceTexture_create(sp<SurfaceTexture> consumer,
-                                        sp<IGraphicBufferProducer> producer);
-
 } // namespace android
 
 #endif // _ANDROID_GRAPHICS_SURFACE_TEXTURE_PLATFORM_H
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 3b6a241..483fb25 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -7,6 +7,41 @@
     AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
     AChoreographer_registerRefreshRateCallback; # apex # introduced=30
     AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
+    AChoreographer_create; # apex # introduced=30
+    AChoreographer_destroy; # apex # introduced=30
+    AChoreographer_getFd; # apex # introduced=30
+    AChoreographer_handlePendingEvents; # apex # introduced=30
+    ASurfaceTexture_fromSurfaceTexture; # apex # introduced=30
+    ASurfaceTexture_release; # apex # introduced=30
   local:
     *;
 };
+
+LIBNATIVEDISPLAY_PLATFORM {
+  global:
+    extern "C++" {
+      android::ADisplay_acquirePhysicalDisplays*;
+      android::ADisplay_release*;
+      android::ADisplay_getMaxSupportedFps*;
+      android::ADisplay_getDisplayType*;
+      android::ADisplay_getPreferredWideColorFormat*;
+      android::ADisplay_getCurrentConfig*;
+      android::ADisplayConfig_getDensity*;
+      android::ADisplayConfig_getWidth*;
+      android::ADisplayConfig_getHeight*;
+      android::ADisplayConfig_getFps*;
+      android::ADisplayConfig_getCompositorOffsetNanos*;
+      android::ADisplayConfig_getAppVsyncOffsetNanos*;
+      android::ASurfaceTexture_getCurrentTextureTarget*;
+      android::ASurfaceTexture_takeConsumerOwnership*;
+      android::ASurfaceTexture_releaseConsumerOwnership*;
+      android::ASurfaceTexture_dequeueBuffer*;
+      android::SurfaceTexture*;
+    };
+    ASurfaceTexture_acquireANativeWindow;
+    ASurfaceTexture_attachToGLContext;
+    ASurfaceTexture_detachFromGLContext;
+    ASurfaceTexture_getTimestamp;
+    ASurfaceTexture_getTransformMatrix;
+    ASurfaceTexture_updateTexImage;
+} LIBNATIVEDISPLAY;
diff --git a/libs/gui/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
similarity index 99%
rename from libs/gui/surfacetexture/EGLConsumer.cpp
rename to libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 1f0f52c..2f31888 100644
--- a/libs/gui/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -24,8 +24,8 @@
 #include <cutils/compiler.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
-#include <gui/surfacetexture/EGLConsumer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
+#include <surfacetexture/EGLConsumer.h>
+#include <surfacetexture/SurfaceTexture.h>
 #include <inttypes.h>
 #include <private/gui/SyncFeatures.h>
 #include <utils/Log.h>
diff --git a/libs/gui/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
similarity index 97%
rename from libs/gui/surfacetexture/ImageConsumer.cpp
rename to libs/nativedisplay/surfacetexture/ImageConsumer.cpp
index 4bc4a7b..16afc68 100644
--- a/libs/gui/surfacetexture/ImageConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp
@@ -15,8 +15,8 @@
  */
 
 #include <gui/BufferQueue.h>
-#include <gui/surfacetexture/ImageConsumer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
+#include <surfacetexture/ImageConsumer.h>
+#include <surfacetexture/SurfaceTexture.h>
 
 // Macro for including the SurfaceTexture name in log messages
 #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
diff --git a/libs/gui/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
similarity index 90%
rename from libs/gui/surfacetexture/SurfaceTexture.cpp
rename to libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index 25e5618..62db6d0 100644
--- a/libs/gui/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -16,9 +16,9 @@
 
 #include <cutils/compiler.h>
 #include <gui/BufferQueue.h>
-#include <gui/surfacetexture/ImageConsumer.h>
-#include <gui/surfacetexture/SurfaceTexture.h>
-#include <gui/surfacetexture/surface_texture_platform.h>
+#include <surfacetexture/ImageConsumer.h>
+#include <surfacetexture/SurfaceTexture.h>
+#include <surfacetexture/surface_texture_platform.h>
 #include <math/mat4.h>
 #include <system/window.h>
 #include <utils/Trace.h>
@@ -487,42 +487,4 @@
     return buffer;
 }
 
-unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) {
-    return st->consumer->getCurrentTextureTarget();
-}
-
-void ASurfaceTexture_takeConsumerOwnership(ASurfaceTexture* texture) {
-    texture->consumer->takeConsumerOwnership();
-}
-
-void ASurfaceTexture_releaseConsumerOwnership(ASurfaceTexture* texture) {
-    texture->consumer->releaseConsumerOwnership();
-}
-
-AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
-                                               android_dataspace* outDataspace,
-                                               float* outTransformMatrix, bool* outNewContent,
-                                               ASurfaceTexture_createReleaseFence createFence,
-                                               ASurfaceTexture_fenceWait fenceWait, void* handle) {
-    sp<GraphicBuffer> buffer;
-    *outNewContent = false;
-    bool queueEmpty;
-    do {
-        buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix,
-                                             &queueEmpty, createFence, fenceWait, handle);
-        if (!queueEmpty) {
-            *outNewContent = true;
-        }
-    } while (buffer.get() && (!queueEmpty));
-    return reinterpret_cast<AHardwareBuffer*>(buffer.get());
-}
-
-ASurfaceTexture* ASurfaceTexture_create(sp<SurfaceTexture> consumer,
-                                        sp<IGraphicBufferProducer> producer) {
-    ASurfaceTexture* ast = new ASurfaceTexture;
-    ast->consumer = consumer;
-    ast->producer = producer;
-    return ast;
-}
-
 } // namespace android
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
new file mode 100644
index 0000000..1670fbb
--- /dev/null
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/surface_texture.h>
+#include <android/surface_texture_jni.h>
+
+#define LOG_TAG "ASurfaceTexture"
+
+#include <utils/Log.h>
+
+#include <gui/Surface.h>
+
+#include <surfacetexture/surface_texture_platform.h>
+#include <surfacetexture/SurfaceTexture.h>
+
+#include <mutex>
+
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+struct ASurfaceTexture {
+    android::sp<android::SurfaceTexture> consumer;
+    android::sp<android::IGraphicBufferProducer> producer;
+};
+
+using namespace android;
+
+const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
+
+struct fields_t {
+    jfieldID  surfaceTexture;
+    jfieldID  producer;
+};
+static fields_t fields;
+static std::once_flag sInitFieldsOnce;
+
+#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
+#define ANDROID_GRAPHICS_PRODUCER_JNI_ID "mProducer"
+
+static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
+{
+    fields.surfaceTexture = env->GetFieldID(clazz,
+            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "J");
+    if (fields.surfaceTexture == NULL) {
+        ALOGE("can't find android/graphics/SurfaceTexture.%s",
+                ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
+    }
+    fields.producer = env->GetFieldID(clazz,
+            ANDROID_GRAPHICS_PRODUCER_JNI_ID, "J");
+    if (fields.producer == NULL) {
+        ALOGE("can't find android/graphics/SurfaceTexture.%s",
+                ANDROID_GRAPHICS_PRODUCER_JNI_ID);
+    }
+}
+
+static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
+    jclass clazz = env->FindClass(class_name);
+    LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
+    return clazz;
+}
+
+static void register_android_graphics_SurfaceTexture(JNIEnv* env)
+{
+    // Cache some fields.
+    ScopedLocalRef<jclass> klass(env, FindClassOrDie(env, kSurfaceTextureClassPathName));
+    SurfaceTexture_classInit(env, klass.get());
+}
+
+static bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
+    std::call_once(sInitFieldsOnce, [=]() {
+        register_android_graphics_SurfaceTexture(env);
+    });
+
+    jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
+    return env->IsInstanceOf(thiz, surfaceTextureClass);
+}
+
+static sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
+    std::call_once(sInitFieldsOnce, [=]() {
+        register_android_graphics_SurfaceTexture(env);
+    });
+
+    return (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
+}
+
+static sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
+    std::call_once(sInitFieldsOnce, [=]() {
+        register_android_graphics_SurfaceTexture(env);
+    });
+
+    return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
+}
+
+// The following functions implement NDK API.
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+    if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) {
+        return nullptr;
+    }
+    ASurfaceTexture* ast = new ASurfaceTexture;
+    ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
+    ast->producer = SurfaceTexture_getProducer(env, surfacetexture);
+    return ast;
+}
+
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
+    sp<Surface> surface = new Surface(st->producer);
+    ANativeWindow* win(surface.get());
+    ANativeWindow_acquire(win);
+    return win;
+}
+
+void ASurfaceTexture_release(ASurfaceTexture* st) {
+    delete st;
+}
+
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t tex) {
+    return st->consumer->attachToContext(tex);
+}
+
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) {
+    return st->consumer->detachFromContext();
+}
+
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) {
+    return st->consumer->updateTexImage();
+}
+
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+    st->consumer->getTransformMatrix(mtx);
+}
+
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) {
+    return st->consumer->getTimestamp();
+}
+
+// The following functions are private/unstable API.
+namespace android {
+
+unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) {
+    return st->consumer->getCurrentTextureTarget();
+}
+
+void ASurfaceTexture_takeConsumerOwnership(ASurfaceTexture* texture) {
+    texture->consumer->takeConsumerOwnership();
+}
+
+void ASurfaceTexture_releaseConsumerOwnership(ASurfaceTexture* texture) {
+    texture->consumer->releaseConsumerOwnership();
+}
+
+AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
+                                               android_dataspace* outDataspace,
+                                               float* outTransformMatrix, bool* outNewContent,
+                                               ASurfaceTexture_createReleaseFence createFence,
+                                               ASurfaceTexture_fenceWait fenceWait, void* handle) {
+    sp<GraphicBuffer> buffer;
+    *outNewContent = false;
+    bool queueEmpty;
+    do {
+        buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix,
+                                             &queueEmpty, createFence, fenceWait, handle);
+        if (!queueEmpty) {
+            *outNewContent = true;
+        }
+    } while (buffer.get() && (!queueEmpty));
+    return reinterpret_cast<AHardwareBuffer*>(buffer.get());
+}
+
+} // namespace android
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 1814ab5..14f7214 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -34,12 +34,12 @@
 #include <cutils/native_handle.h>
 #include <errno.h>
 #include <limits.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
 #include <sys/cdefs.h>
 #include <system/graphics.h>
 #include <unistd.h>
-#include <stdbool.h>
 
 // system/window.h is a superset of the vndk and apex apis
 #include <apex/window.h>
@@ -247,6 +247,7 @@
     NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT             = 37,    /* private */
     NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION       = 38,    /* private */
     NATIVE_WINDOW_GET_LAST_QUEUE_DURATION         = 39,    /* private */
+    NATIVE_WINDOW_SET_FRAME_RATE                  = 40,
     // clang-format on
 };
 
@@ -1008,4 +1009,8 @@
     return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
 }
 
+static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate) {
+    return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate);
+}
+
 __END_DECLS
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 348377e..2e3ab4c 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -57,6 +57,10 @@
         "gl/ImageManager.cpp",
         "gl/Program.cpp",
         "gl/ProgramCache.cpp",
+        "gl/filters/BlurFilter.cpp",
+        "gl/filters/LensBlurFilter.cpp",
+        "gl/filters/GaussianBlurFilter.cpp",
+        "gl/filters/GenericProgram.cpp",
     ],
 }
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 0748dfb..09659fe 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -49,6 +49,9 @@
 #include "GLShadowVertexGenerator.h"
 #include "Program.h"
 #include "ProgramCache.h"
+#include "filters/BlurFilter.h"
+#include "filters/GaussianBlurFilter.h"
+#include "filters/LensBlurFilter.h"
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
@@ -422,6 +425,18 @@
         mTraceGpuCompletion = true;
         mFlushTracer = std::make_unique<FlushTracer>(this);
     }
+
+    if (args.supportsBackgroundBlur) {
+        char isGaussian[PROPERTY_VALUE_MAX];
+        property_get("debug.sf.gaussianBlur", isGaussian, "1");
+        if (atoi(isGaussian)) {
+            mBlurFilter = new GaussianBlurFilter(*this);
+        } else {
+            mBlurFilter = new LensBlurFilter(*this);
+        }
+        checkErrors("BlurFilter creation");
+    }
+
     mImageManager = std::make_unique<ImageManager>(this);
     mDrawingBuffer = createFramebuffer();
 }
@@ -871,11 +886,19 @@
 }
 
 void GLESRenderEngine::checkErrors() const {
+    checkErrors(nullptr);
+}
+
+void GLESRenderEngine::checkErrors(const char* tag) const {
     do {
         // there could be more than one error flag
         GLenum error = glGetError();
         if (error == GL_NO_ERROR) break;
-        ALOGE("GL error 0x%04x", int(error));
+        if (tag == nullptr) {
+            ALOGE("GL error 0x%04x", int(error));
+        } else {
+            ALOGE("GL error: %s -> 0x%04x", tag, int(error));
+        }
     } while (true);
 }
 
@@ -957,13 +980,36 @@
         return BAD_VALUE;
     }
 
-    BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
+    std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
+    // Let's find the topmost layer requesting background blur (if any.)
+    // Blurs in multiple layers are not supported, given the cost of the shader.
+    const LayerSettings* blurLayer = nullptr;
+    if (CC_LIKELY(mBlurFilter != nullptr)) {
+        for (auto const& layer : layers) {
+            if (layer.backgroundBlurRadius > 0) {
+                blurLayer = &layer;
+            }
+        }
+    }
 
-    if (fbo.getStatus() != NO_ERROR) {
-        ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
-              buffer->handle);
-        checkErrors();
-        return fbo.getStatus();
+    if (blurLayer == nullptr) {
+        fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache);
+        if (fbo->getStatus() != NO_ERROR) {
+            ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+                  buffer->handle);
+            checkErrors();
+            return fbo->getStatus();
+        }
+        setViewportAndProjection(display.physicalDisplay, display.clip);
+    } else {
+        setViewportAndProjection(display.physicalDisplay, display.clip);
+        auto status = mBlurFilter->setAsDrawTarget(display);
+        if (status != NO_ERROR) {
+            ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
+                  buffer->handle);
+            checkErrors();
+            return status;
+        }
     }
 
     // clear the entire buffer, sometimes when we reuse buffers we'd persist
@@ -973,8 +1019,6 @@
     // opaque layers.
     clearWithColor(0.0, 0.0, 0.0, 0.0);
 
-    setViewportAndProjection(display.physicalDisplay, display.clip);
-
     setOutputDataSpace(display.outputDataspace);
     setDisplayMaxLuminance(display.maxLuminance);
 
@@ -991,7 +1035,36 @@
                         .setTexCoords(2 /* size */)
                         .setCropCoords(2 /* size */)
                         .build();
-    for (auto layer : layers) {
+    for (auto const& layer : layers) {
+        if (blurLayer == &layer) {
+            auto status = mBlurFilter->prepare(layer.backgroundBlurRadius);
+            if (status != NO_ERROR) {
+                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
+                      buffer->handle);
+                checkErrors("Can't render first blur pass");
+                return status;
+            }
+
+            fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
+                                                                  useFramebufferCache);
+            status = fbo->getStatus();
+            if (status != NO_ERROR) {
+                ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+                      buffer->handle);
+                checkErrors("Can't bind native framebuffer");
+                return status;
+            }
+            setViewportAndProjection(display.physicalDisplay, display.clip);
+
+            status = mBlurFilter->render();
+            if (status != NO_ERROR) {
+                ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
+                      buffer->handle);
+                checkErrors("Can't render blur filter");
+                return status;
+            }
+        }
+
         mState.maxMasteringLuminance = layer.source.buffer.maxMasteringLuminance;
         mState.maxContentLuminance = layer.source.buffer.maxContentLuminance;
         mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index f41eda2..547235a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -46,6 +46,7 @@
 namespace gl {
 
 class GLImage;
+class BlurFilter;
 
 class GLESRenderEngine : public impl::RenderEngine {
 public:
@@ -117,6 +118,7 @@
     std::unique_ptr<Framebuffer> createFramebuffer();
     std::unique_ptr<Image> createImage();
     void checkErrors() const;
+    void checkErrors(const char* tag) const;
     void setScissor(const Rect& region);
     void disableScissor();
     bool waitSync(EGLSyncKHR sync, EGLint flags);
@@ -228,6 +230,9 @@
 
     std::unique_ptr<Framebuffer> mDrawingBuffer;
 
+    // Blur effect processor, only instantiated when a layer requests it.
+    BlurFilter* mBlurFilter = nullptr;
+
     class FlushTracer {
     public:
         FlushTracer(GLESRenderEngine* engine);
@@ -251,6 +256,11 @@
     };
     friend class FlushTracer;
     friend class ImageManager;
+    friend class GLFramebuffer;
+    friend class BlurFilter;
+    friend class GaussianBlurFilter;
+    friend class LensBlurFilter;
+    friend class GenericProgram;
     std::unique_ptr<FlushTracer> mFlushTracer;
     std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
 };
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 5fbb5ba..091eac9 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -20,8 +20,8 @@
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
-#include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
 #include <gui/DebugEGLImageTracker.h>
 #include <nativebase/nativebase.h>
 #include <utils/Trace.h>
@@ -32,14 +32,23 @@
 namespace gl {
 
 GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine)
+      : GLFramebuffer(engine, false /* multiTarget */) {}
+
+GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine, bool multiTarget)
       : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
     glGenTextures(1, &mTextureName);
+    if (multiTarget) {
+        glGenTextures(1, &mSecondaryTextureName);
+    }
     glGenFramebuffers(1, &mFramebufferName);
 }
 
 GLFramebuffer::~GLFramebuffer() {
     glDeleteFramebuffers(1, &mFramebufferName);
     glDeleteTextures(1, &mTextureName);
+    if (mSecondaryTextureName != -1) {
+        glDeleteTextures(1, &mSecondaryTextureName);
+    }
 }
 
 bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
@@ -68,6 +77,55 @@
     return true;
 }
 
+void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height) {
+    ATRACE_CALL();
+
+    glBindTexture(GL_TEXTURE_2D, mTextureName);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+
+    const bool multiTarget = mSecondaryTextureName != -1;
+    if (multiTarget) {
+        glBindTexture(GL_TEXTURE_2D, mSecondaryTextureName);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+    }
+
+    mBufferHeight = height;
+    mBufferWidth = width;
+    mEngine.checkErrors("Allocating Fbo texture");
+
+    bind();
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureName, 0);
+    if (multiTarget) {
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D,
+                               mSecondaryTextureName, 0);
+        GLenum buffers[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
+        glDrawBuffers(2, buffers);
+    }
+    mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    unbind();
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    if (mStatus != GL_FRAMEBUFFER_COMPLETE) {
+        ALOGE("Frame buffer is not complete. Error %d", mStatus);
+    }
+}
+
+void GLFramebuffer::bind() const {
+    glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
+}
+
+void GLFramebuffer::unbind() const {
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
 } // namespace gl
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index b7650bb..668685a 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -20,6 +20,7 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+#include <GLES2/gl2.h>
 #include <renderengine/Framebuffer.h>
 
 struct ANativeWindowBuffer;
@@ -33,22 +34,30 @@
 class GLFramebuffer : public renderengine::Framebuffer {
 public:
     explicit GLFramebuffer(GLESRenderEngine& engine);
+    explicit GLFramebuffer(GLESRenderEngine& engine, bool multiTarget);
     ~GLFramebuffer() override;
 
     bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
                                const bool useFramebufferCache) override;
+    void allocateBuffers(uint32_t width, uint32_t height);
     EGLImageKHR getEGLImage() const { return mEGLImage; }
     uint32_t getTextureName() const { return mTextureName; }
+    uint32_t getSecondaryTextureName() const { return mSecondaryTextureName; }
     uint32_t getFramebufferName() const { return mFramebufferName; }
     int32_t getBufferHeight() const { return mBufferHeight; }
     int32_t getBufferWidth() const { return mBufferWidth; }
+    GLenum getStatus() const { return mStatus; }
+    void bind() const;
+    void unbind() const;
 
 private:
     GLESRenderEngine& mEngine;
     EGLDisplay mEGLDisplay;
     EGLImageKHR mEGLImage;
     bool usingFramebufferCache = false;
+    GLenum mStatus = GL_FRAMEBUFFER_UNSUPPORTED;
     uint32_t mTextureName, mFramebufferName;
+    uint32_t mSecondaryTextureName = -1;
 
     int32_t mBufferHeight = 0;
     int32_t mBufferWidth = 0;
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
new file mode 100644
index 0000000..a554687
--- /dev/null
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+#include <cstdint>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+BlurFilter::BlurFilter(GLESRenderEngine& engine)
+      : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mSimpleProgram(engine) {
+    mSimpleProgram.compile(getVertexShader(), getSimpleFragShader());
+    mSPosLoc = mSimpleProgram.getAttributeLocation("aPosition");
+    mSUvLoc = mSimpleProgram.getAttributeLocation("aUV");
+    mSTextureLoc = mSimpleProgram.getUniformLocation("uTexture");
+}
+
+status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display) {
+    ATRACE_NAME("BlurFilter::setAsDrawTarget");
+
+    if (!mTexturesAllocated) {
+        const uint32_t fboWidth = floorf(display.physicalDisplay.width() * kFboScale);
+        const uint32_t fboHeight = floorf(display.physicalDisplay.height() * kFboScale);
+        mCompositionFbo.allocateBuffers(fboWidth, fboHeight);
+        mBlurredFbo.allocateBuffers(fboWidth, fboHeight);
+        allocateTextures();
+        mTexturesAllocated = true;
+    }
+
+    if (mBlurredFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+        ALOGE("Invalid blur buffer");
+        return mBlurredFbo.getStatus();
+    }
+    if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+        ALOGE("Invalid composition buffer");
+        return mCompositionFbo.getStatus();
+    }
+
+    mCompositionFbo.bind();
+    glViewport(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight());
+    return NO_ERROR;
+}
+
+void BlurFilter::drawMesh(GLuint uv, GLuint position) {
+    GLfloat positions[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
+    GLfloat texCoords[] = {0.0, 0.0, 0.0, 1.0f, 1.0f, 1.0f, 1.0f, 0};
+
+    // set attributes
+    glEnableVertexAttribArray(uv);
+    glVertexAttribPointer(uv, 2 /* size */, GL_FLOAT, GL_FALSE, 0, texCoords);
+    glEnableVertexAttribArray(position);
+    glVertexAttribPointer(position, 2 /* size */, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
+                          positions);
+
+    // draw mesh
+    glDrawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
+    mEngine.checkErrors("Drawing blur mesh");
+}
+
+status_t BlurFilter::render() {
+    ATRACE_NAME("BlurFilter::render");
+
+    // Now let's scale our blur up
+    mSimpleProgram.useProgram();
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName());
+    glUniform1i(mSTextureLoc, 0);
+    mEngine.checkErrors("Setting final pass uniforms");
+
+    drawMesh(mSUvLoc, mSPosLoc);
+
+    glUseProgram(0);
+    return NO_ERROR;
+}
+
+string BlurFilter::getVertexShader() const {
+    return R"SHADER(
+        #version 310 es
+        precision lowp float;
+
+        in vec2 aPosition;
+        in mediump vec2 aUV;
+        out mediump vec2 vUV;
+
+        void main() {
+            vUV = aUV;
+            gl_Position = vec4(aPosition, 0.0, 1.0);
+        }
+    )SHADER";
+}
+
+string BlurFilter::getSimpleFragShader() const {
+    string shader = R"SHADER(
+        #version 310 es
+        precision lowp float;
+
+        in mediump vec2 vUV;
+        out vec4 fragColor;
+
+        uniform sampler2D uTexture;
+
+        void main() {
+            fragColor = texture(uTexture, vUV);
+        }
+    )SHADER";
+    return shader;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
new file mode 100644
index 0000000..2b5ea58
--- /dev/null
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class BlurFilter {
+public:
+    // Downsample FBO to improve performance
+    static constexpr float kFboScale = 0.35f;
+
+    explicit BlurFilter(GLESRenderEngine& engine);
+    virtual ~BlurFilter(){};
+
+    // Set up render targets, redirecting output to offscreen texture.
+    status_t setAsDrawTarget(const DisplaySettings&);
+    // Allocate any textures needed for the filter.
+    virtual void allocateTextures() = 0;
+    // Execute blur passes, rendering to offscreen texture.
+    virtual status_t prepare(uint32_t radius) = 0;
+    // Render blur to the bound framebuffer (screen).
+    status_t render();
+
+protected:
+    void drawMesh(GLuint uv, GLuint position);
+    string getSimpleFragShader() const;
+    string getVertexShader() const;
+
+    GLESRenderEngine& mEngine;
+    // Frame buffer holding the composited background.
+    GLFramebuffer mCompositionFbo;
+    // Frame buffer holding the blur result.
+    GLFramebuffer mBlurredFbo;
+
+private:
+    bool mTexturesAllocated = false;
+
+    GenericProgram mSimpleProgram;
+    GLuint mSPosLoc;
+    GLuint mSUvLoc;
+    GLuint mSTextureLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
new file mode 100644
index 0000000..b1ad72c
--- /dev/null
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GaussianBlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+#include <cstdint>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine)
+      : BlurFilter(engine),
+        mVerticalPassFbo(engine),
+        mVerticalProgram(engine),
+        mHorizontalProgram(engine) {
+    mVerticalProgram.compile(getVertexShader(), getFragmentShader(false));
+    mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition");
+    mVUvLoc = mVerticalProgram.getAttributeLocation("aUV");
+    mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture");
+    mVSizeLoc = mVerticalProgram.getUniformLocation("uSize");
+    mVRadiusLoc = mVerticalProgram.getUniformLocation("uRadius");
+
+    mHorizontalProgram.compile(getVertexShader(), getFragmentShader(true));
+    mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition");
+    mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV");
+    mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture");
+    mHSizeLoc = mHorizontalProgram.getUniformLocation("uSize");
+    mHRadiusLoc = mHorizontalProgram.getUniformLocation("uRadius");
+}
+
+void GaussianBlurFilter::allocateTextures() {
+    mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight());
+}
+
+status_t GaussianBlurFilter::prepare(uint32_t radius) {
+    ATRACE_NAME("GaussianBlurFilter::prepare");
+
+    if (mVerticalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+        ALOGE("Invalid vertical FBO");
+        return mVerticalPassFbo.getStatus();
+    }
+    if (!mVerticalProgram.isValid()) {
+        ALOGE("Invalid vertical shader");
+        return GL_INVALID_OPERATION;
+    }
+    if (!mHorizontalProgram.isValid()) {
+        ALOGE("Invalid horizontal shader");
+        return GL_INVALID_OPERATION;
+    }
+
+    // First, we'll apply the vertical pass, that receives the flattened background layers.
+    mVerticalPassFbo.bind();
+    mVerticalProgram.useProgram();
+
+    // set uniforms
+    auto width = mVerticalPassFbo.getBufferWidth();
+    auto height = mVerticalPassFbo.getBufferHeight();
+    glViewport(0, 0, width, height);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+    glUniform1i(mVTextureLoc, 0);
+    glUniform2f(mVSizeLoc, width, height);
+    glUniform1f(mVRadiusLoc, radius * kFboScale);
+    mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
+
+    drawMesh(mVUvLoc, mVPosLoc);
+
+    // Blur vertically on a secondary pass
+    mBlurredFbo.bind();
+    mHorizontalProgram.useProgram();
+
+    // set uniforms
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName());
+    glUniform1i(mHTextureLoc, 0);
+    glUniform2f(mHSizeLoc, width, height);
+    glUniform1f(mHRadiusLoc, radius * kFboScale);
+    mEngine.checkErrors("Setting vertical pass uniforms");
+
+    drawMesh(mHUvLoc, mHPosLoc);
+
+    // reset active texture
+    mBlurredFbo.unbind();
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    // unbind program
+    glUseProgram(0);
+
+    return NO_ERROR;
+}
+
+string GaussianBlurFilter::getFragmentShader(bool horizontal) const {
+    string shader = "#version 310 es\n#define DIRECTION ";
+    shader += (horizontal ? "1" : "0");
+    shader += R"SHADER(
+        precision lowp float;
+
+        uniform sampler2D uTexture;
+        uniform vec2 uSize;
+        uniform float uRadius;
+
+        in mediump vec2 vUV;
+
+        out vec4 fragColor;
+
+        #define PI 3.14159265359
+        #define THETA 0.352
+        #define MU 0.0
+        #define A 1.0 / (THETA * sqrt(2.0 * PI))
+        #define K 1.0 / (2.0 * THETA * THETA)
+        #define MAX_SAMPLES 12
+
+        float gaussianBellCurve(float x) {
+            float tmp = (x - MU);
+            return exp(-K * tmp * tmp);
+        }
+
+        vec3 gaussianBlur(sampler2D texture, mediump vec2 uv, float size,
+                          vec2 direction, float radius) {
+            float totalWeight = 0.0;
+            vec3 blurred = vec3(0.);
+            int samples = min(int(floor(radius / 2.0)), MAX_SAMPLES);
+            float inc = radius / (size * 2.0);
+
+            for (int i = -samples; i <= samples; i++) {
+                float normalized = (float(i) / float(samples));
+                float weight = gaussianBellCurve(normalized);
+                float radInc = inc * normalized;
+                blurred += weight * (texture(texture, uv + radInc * direction)).rgb;;
+                totalWeight += weight;
+            }
+
+            return blurred / totalWeight;
+        }
+
+        void main() {
+            #if DIRECTION == 1
+            vec3 color = gaussianBlur(uTexture, vUV, uSize.x, vec2(1.0, 0.0), uRadius);
+            #else
+            vec3 color = gaussianBlur(uTexture, vUV, uSize.y, vec2(0.0, 1.0), uRadius);
+            #endif
+            fragColor = vec4(color.r, color.g, color.b, texture(uTexture, vUV).a);
+        }
+
+    )SHADER";
+    return shader;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h
new file mode 100644
index 0000000..acf0f07
--- /dev/null
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "BlurFilter.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GaussianBlurFilter : public BlurFilter {
+public:
+    explicit GaussianBlurFilter(GLESRenderEngine& engine);
+    status_t prepare(uint32_t radius) override;
+    void allocateTextures() override;
+
+private:
+    string getFragmentShader(bool horizontal) const;
+
+    // Initial, vertical render pass
+    GLFramebuffer mVerticalPassFbo;
+
+    // Vertical pass and its uniforms
+    GenericProgram mVerticalProgram;
+    GLuint mVPosLoc;
+    GLuint mVUvLoc;
+    GLuint mVTextureLoc;
+    GLuint mVSizeLoc;
+    GLuint mVRadiusLoc;
+
+    // Horizontal pass and its uniforms
+    GenericProgram mHorizontalProgram;
+    GLuint mHPosLoc;
+    GLuint mHUvLoc;
+    GLuint mHTextureLoc;
+    GLuint mHSizeLoc;
+    GLuint mHRadiusLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/gl/filters/GenericProgram.cpp b/libs/renderengine/gl/filters/GenericProgram.cpp
new file mode 100644
index 0000000..bb35889
--- /dev/null
+++ b/libs/renderengine/gl/filters/GenericProgram.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GenericProgram.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GenericProgram::GenericProgram(GLESRenderEngine& engine) : mEngine(engine) {}
+
+GenericProgram::~GenericProgram() {
+    if (mVertexShaderHandle != 0) {
+        if (mProgramHandle != 0) {
+            glDetachShader(mProgramHandle, mVertexShaderHandle);
+        }
+        glDeleteShader(mVertexShaderHandle);
+    }
+
+    if (mFragmentShaderHandle != 0) {
+        if (mProgramHandle != 0) {
+            glDetachShader(mProgramHandle, mFragmentShaderHandle);
+        }
+        glDeleteShader(mFragmentShaderHandle);
+    }
+
+    if (mProgramHandle != 0) {
+        glDeleteProgram(mProgramHandle);
+    }
+}
+
+void GenericProgram::compile(string vertexShader, string fragmentShader) {
+    mVertexShaderHandle = compileShader(GL_VERTEX_SHADER, vertexShader);
+    mFragmentShaderHandle = compileShader(GL_FRAGMENT_SHADER, fragmentShader);
+    if (mVertexShaderHandle == 0 || mFragmentShaderHandle == 0) {
+        ALOGE("Aborting program creation.");
+        return;
+    }
+    mProgramHandle = createAndLink(mVertexShaderHandle, mFragmentShaderHandle);
+    mEngine.checkErrors("Linking program");
+}
+
+void GenericProgram::useProgram() const {
+    glUseProgram(mProgramHandle);
+}
+
+GLuint GenericProgram::compileShader(GLuint type, string src) const {
+    const GLuint shader = glCreateShader(type);
+    if (shader == 0) {
+        mEngine.checkErrors("Creating shader");
+        return 0;
+    }
+    const GLchar* charSrc = (const GLchar*)src.c_str();
+    glShaderSource(shader, 1, &charSrc, nullptr);
+    glCompileShader(shader);
+
+    GLint isCompiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+    if (isCompiled == GL_FALSE) {
+        GLint maxLength = 0;
+        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
+        string errorLog;
+        errorLog.reserve(maxLength);
+        glGetShaderInfoLog(shader, maxLength, &maxLength, errorLog.data());
+        glDeleteShader(shader);
+        ALOGE("Error compiling shader: %s", errorLog.c_str());
+        return 0;
+    }
+    return shader;
+}
+GLuint GenericProgram::createAndLink(GLuint vertexShader, GLuint fragmentShader) const {
+    const GLuint program = glCreateProgram();
+    mEngine.checkErrors("Creating program");
+
+    glAttachShader(program, vertexShader);
+    glAttachShader(program, fragmentShader);
+    glLinkProgram(program);
+    mEngine.checkErrors("Linking program");
+    return program;
+}
+
+GLuint GenericProgram::getUniformLocation(const string name) const {
+    if (mProgramHandle == 0) {
+        ALOGE("Can't get location of %s on an invalid program.", name.c_str());
+        return -1;
+    }
+    return glGetUniformLocation(mProgramHandle, (const GLchar*)name.c_str());
+}
+
+GLuint GenericProgram::getAttributeLocation(const string name) const {
+    if (mProgramHandle == 0) {
+        ALOGE("Can't get location of %s on an invalid program.", name.c_str());
+        return -1;
+    }
+    return glGetAttribLocation(mProgramHandle, (const GLchar*)name.c_str());
+}
+
+bool GenericProgram::isValid() const {
+    return mProgramHandle != 0;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/GenericProgram.h b/libs/renderengine/gl/filters/GenericProgram.h
new file mode 100644
index 0000000..6da2a5a
--- /dev/null
+++ b/libs/renderengine/gl/filters/GenericProgram.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GenericProgram {
+public:
+    explicit GenericProgram(GLESRenderEngine& renderEngine);
+    ~GenericProgram();
+    void compile(string vertexShader, string fragmentShader);
+    bool isValid() const;
+    void useProgram() const;
+    GLuint getAttributeLocation(const string name) const;
+    GLuint getUniformLocation(const string name) const;
+
+private:
+    GLuint compileShader(GLuint type, const string src) const;
+    GLuint createAndLink(GLuint vertexShader, GLuint fragmentShader) const;
+
+    GLESRenderEngine& mEngine;
+    GLuint mVertexShaderHandle = 0;
+    GLuint mFragmentShaderHandle = 0;
+    GLuint mProgramHandle = 0;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.cpp b/libs/renderengine/gl/filters/LensBlurFilter.cpp
new file mode 100644
index 0000000..386bd91
--- /dev/null
+++ b/libs/renderengine/gl/filters/LensBlurFilter.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LensBlurFilter.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <ui/GraphicTypes.h>
+#include <cstdint>
+
+#include <utils/Trace.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+// Number of blur samples in shader (for loop)
+static constexpr auto kNumSamples = 12;
+
+LensBlurFilter::LensBlurFilter(GLESRenderEngine& engine)
+      : BlurFilter(engine),
+        mVerticalDiagonalPassFbo(engine, true /* multiTarget */),
+        mVerticalDiagonalProgram(engine),
+        mCombinedProgram(engine) {
+    mVerticalDiagonalProgram.compile(getVertexShader(), getFragmentShader(false));
+    mCombinedProgram.compile(getVertexShader(), getFragmentShader(true));
+
+    mVDPosLoc = mVerticalDiagonalProgram.getAttributeLocation("aPosition");
+    mVDUvLoc = mVerticalDiagonalProgram.getAttributeLocation("aUV");
+    mVDTexture0Loc = mVerticalDiagonalProgram.getUniformLocation("uTexture0");
+    mVDSizeLoc = mVerticalDiagonalProgram.getUniformLocation("uSize");
+    mVDRadiusLoc = mVerticalDiagonalProgram.getUniformLocation("uRadius");
+    mVDNumSamplesLoc = mVerticalDiagonalProgram.getUniformLocation("uNumSamples");
+
+    mCPosLoc = mCombinedProgram.getAttributeLocation("aPosition");
+    mCUvLoc = mCombinedProgram.getAttributeLocation("aUV");
+    mCTexture0Loc = mCombinedProgram.getUniformLocation("uTexture0");
+    mCTexture1Loc = mCombinedProgram.getUniformLocation("uTexture1");
+    mCSizeLoc = mCombinedProgram.getUniformLocation("uSize");
+    mCRadiusLoc = mCombinedProgram.getUniformLocation("uRadius");
+    mCNumSamplesLoc = mCombinedProgram.getUniformLocation("uNumSamples");
+}
+
+void LensBlurFilter::allocateTextures() {
+    mVerticalDiagonalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(),
+                                             mBlurredFbo.getBufferHeight());
+}
+
+status_t LensBlurFilter::prepare(uint32_t radius) {
+    ATRACE_NAME("LensBlurFilter::prepare");
+
+    if (mVerticalDiagonalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) {
+        ALOGE("Invalid vertical-diagonal FBO");
+        return mVerticalDiagonalPassFbo.getStatus();
+    }
+    if (!mVerticalDiagonalProgram.isValid()) {
+        ALOGE("Invalid vertical-diagonal shader");
+        return GL_INVALID_OPERATION;
+    }
+    if (!mCombinedProgram.isValid()) {
+        ALOGE("Invalid blur shader");
+        return GL_INVALID_OPERATION;
+    }
+
+    // First, we'll apply the vertical/diagonal pass, that receives the flattened background layers,
+    // and writes the output to two textures (vertical and diagonal.)
+    mVerticalDiagonalPassFbo.bind();
+    mVerticalDiagonalProgram.useProgram();
+
+    // set uniforms
+    auto width = mVerticalDiagonalPassFbo.getBufferWidth();
+    auto height = mVerticalDiagonalPassFbo.getBufferHeight();
+    glViewport(0, 0, width, height);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName());
+    glUniform1i(mVDTexture0Loc, 0);
+    glUniform2f(mVDSizeLoc, width, height);
+    glUniform1f(mVDRadiusLoc, radius * kFboScale);
+    glUniform1i(mVDNumSamplesLoc, kNumSamples);
+    mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
+
+    drawMesh(mVDUvLoc, mVDPosLoc);
+
+    // Now we'll combine the multi render pass into a blurred image
+    mBlurredFbo.bind();
+    mCombinedProgram.useProgram();
+
+    // set uniforms
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getTextureName());
+    glUniform1i(mCTexture0Loc, 0);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getSecondaryTextureName());
+    glUniform1i(mCTexture1Loc, 1);
+    glUniform2f(mCSizeLoc, width, height);
+    glUniform1f(mCRadiusLoc, radius * kFboScale);
+    glUniform1i(mCNumSamplesLoc, kNumSamples);
+    mEngine.checkErrors("Setting vertical pass uniforms");
+
+    drawMesh(mCUvLoc, mCPosLoc);
+
+    // reset active texture
+    mBlurredFbo.unbind();
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    // unbind program
+    glUseProgram(0);
+
+    return NO_ERROR;
+}
+
+string LensBlurFilter::getFragmentShader(bool forComposition) const {
+    string shader = "#version 310 es\n#define DIRECTION ";
+    shader += (forComposition ? "1" : "0");
+    shader += R"SHADER(
+        precision lowp float;
+
+        #define BOKEH_ANGLE 0.0
+        #define PI 3.14159265359
+
+        uniform sampler2D uTexture0;
+        uniform vec2 uSize;
+        uniform float uRadius;
+        uniform int uNumSamples;
+
+        in mediump vec2 vUV;
+
+        #if DIRECTION == 0
+        layout(location = 0) out vec4 fragColor0;
+        layout(location = 1) out vec4 fragColor1;
+        #else
+        uniform sampler2D uTexture1;
+        out vec4 fragColor;
+        #endif
+
+        vec4 blur(const sampler2D tex, in vec2 uv, const vec2 direction, float radius,
+                  in int samples, float intensity) {
+            vec4 finalColor = vec4(vec3(0.0), 1.0);
+            float blurAmount = 0.0;
+            uv += direction * 0.5;
+
+            for (int i = 0; i < samples; i++){
+                float delta = radius * float(i) / float(samples);
+                vec4 color = texture(tex, uv + direction * delta);
+                color.rgb *= intensity;
+                color *= color.a;
+                blurAmount += color.a;
+                finalColor += color;
+            }
+
+            return finalColor / blurAmount;
+        }
+
+        vec4 blur(const sampler2D tex, in vec2 uv, const vec2 direction, float radius,
+                  in int samples) {
+            return blur(tex, uv, direction, radius, samples, 1.0);
+        }
+
+        vec4[2] verticalDiagonalLensBlur (vec2 uv, sampler2D texture, vec2 resolution,
+                                          float radius, int samples) {
+            float coc = texture(texture, uv).a;
+
+            // Vertical Blur
+            vec2 blurDirV = (coc / resolution.xy) * vec2(cos(BOKEH_ANGLE + PI / 2.0),
+                sin(BOKEH_ANGLE + PI / 2.0));
+            vec3 colorV = blur(texture, uv, blurDirV, radius, samples).rgb * coc;
+
+            // Diagonal Blur
+            vec2 blurDirD = (coc / resolution.xy) * vec2(cos(BOKEH_ANGLE - PI / 6.0),
+                sin(BOKEH_ANGLE - PI / 6.0));
+            vec3 colorD = blur(texture, uv, blurDirD, radius, samples).rgb * coc;
+
+            vec4 composed[2];
+            composed[0] = vec4(colorV, coc);
+            // added * 0.5, to remap
+            composed[1] = vec4((colorD + colorV) * 0.5, coc);
+
+            return composed;
+        }
+
+        vec4 rhombiLensBlur (vec2 uv, sampler2D texture0, sampler2D texture1, vec2 resolution,
+                             float radius, int samples) {
+            float coc1 = texture(texture0, uv).a;
+            float coc2 = texture(texture1, uv).a;
+
+            vec2 blurDirection1 = coc1 / resolution.xy * vec2(cos(BOKEH_ANGLE - PI / 6.0), sin(BOKEH_ANGLE - PI / 6.0));
+            vec3 color1 = blur(texture0, uv, blurDirection1, radius, samples).rgb * coc1;
+
+            vec2 blurDirection2 = coc2 / resolution.xy * vec2(cos(BOKEH_ANGLE - 5.0 * PI / 6.0), sin(BOKEH_ANGLE - 5.0 * PI / 6.0));
+            vec3 color2 = blur(texture1, uv, blurDirection2, radius, samples, 2.0).rgb * coc2;
+
+            return vec4((color1 + color2) * 0.33, 1.0);
+        }
+
+        void main() {
+            #if DIRECTION == 0
+            // First pass: outputs two textures
+            vec4 colorOut[] = verticalDiagonalLensBlur(vUV, uTexture0, uSize, uRadius, uNumSamples);
+            fragColor0 = colorOut[0];
+            fragColor1 = colorOut[1];
+            #else
+            // Second pass: combines both textures into a blurred one.
+            fragColor = rhombiLensBlur(vUV, uTexture0, uTexture1, uSize, uRadius, uNumSamples);
+            #endif
+        }
+
+    )SHADER";
+    return shader;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/filters/LensBlurFilter.h b/libs/renderengine/gl/filters/LensBlurFilter.h
new file mode 100644
index 0000000..8543f0d
--- /dev/null
+++ b/libs/renderengine/gl/filters/LensBlurFilter.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include "../GLESRenderEngine.h"
+#include "../GLFramebuffer.h"
+#include "BlurFilter.h"
+#include "GenericProgram.h"
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class LensBlurFilter : public BlurFilter {
+public:
+    explicit LensBlurFilter(GLESRenderEngine& engine);
+    status_t prepare(uint32_t radius) override;
+    void allocateTextures() override;
+
+private:
+    string getFragmentShader(bool forComposition) const;
+
+    // Intermediate render pass
+    GLFramebuffer mVerticalDiagonalPassFbo;
+
+    // Vertical/diagonal pass and its uniforms
+    GenericProgram mVerticalDiagonalProgram;
+    GLuint mVDPosLoc;
+    GLuint mVDUvLoc;
+    GLuint mVDTexture0Loc;
+    GLuint mVDSizeLoc;
+    GLuint mVDRadiusLoc;
+    GLuint mVDNumSamplesLoc;
+
+    // Blur composition pass and its uniforms
+    GenericProgram mCombinedProgram;
+    GLuint mCPosLoc;
+    GLuint mCUvLoc;
+    GLuint mCTexture0Loc;
+    GLuint mCTexture1Loc;
+    GLuint mCSizeLoc;
+    GLuint mCRadiusLoc;
+    GLuint mCNumSamplesLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 5aa3f3b..3dc198f 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -149,6 +149,8 @@
     bool disableBlending = false;
 
     ShadowSettings shadow;
+
+    int backgroundBlurRadius = 0;
 };
 
 static inline bool operator==(const Buffer& lhs, const Buffer& rhs) {
@@ -182,7 +184,8 @@
     return lhs.geometry == rhs.geometry && lhs.source == rhs.source && lhs.alpha == rhs.alpha &&
             lhs.sourceDataspace == rhs.sourceDataspace &&
             lhs.colorTransform == rhs.colorTransform &&
-            lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow;
+            lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow &&
+            lhs.backgroundBlurRadius == rhs.backgroundBlurRadius;
 }
 
 // Defining PrintTo helps with Google Tests.
@@ -243,6 +246,7 @@
     PrintTo(settings.sourceDataspace, os);
     *os << "\n    .colorTransform = " << settings.colorTransform;
     *os << "\n    .disableBlending = " << settings.disableBlending;
+    *os << "\n    .backgroundBlurRadius = " << settings.backgroundBlurRadius;
     *os << "\n    .shadow = ";
     PrintTo(settings.shadow, os);
     *os << "\n}";
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 4db5c57..e3c2d84 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -174,6 +174,7 @@
     bool useColorManagement;
     bool enableProtectedContext;
     bool precacheToneMapperShaderOnly;
+    bool supportsBackgroundBlur;
     RenderEngine::ContextPriority contextPriority;
 
     struct Builder;
@@ -186,12 +187,14 @@
             bool _useColorManagement,
             bool _enableProtectedContext,
             bool _precacheToneMapperShaderOnly,
+            bool _supportsBackgroundBlur,
             RenderEngine::ContextPriority _contextPriority)
         : pixelFormat(_pixelFormat)
         , imageCacheSize(_imageCacheSize)
         , useColorManagement(_useColorManagement)
         , enableProtectedContext(_enableProtectedContext)
         , precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly)
+        , supportsBackgroundBlur(_supportsBackgroundBlur)
         , contextPriority(_contextPriority) {}
     RenderEngineCreationArgs() = delete;
 };
@@ -219,13 +222,18 @@
         this->precacheToneMapperShaderOnly = precacheToneMapperShaderOnly;
         return *this;
     }
+    Builder& setSupportsBackgroundBlur(bool supportsBackgroundBlur) {
+        this->supportsBackgroundBlur = supportsBackgroundBlur;
+        return *this;
+    }
     Builder& setContextPriority(RenderEngine::ContextPriority contextPriority) {
         this->contextPriority = contextPriority;
         return *this;
     }
     RenderEngineCreationArgs build() const {
         return RenderEngineCreationArgs(pixelFormat, imageCacheSize, useColorManagement,
-                enableProtectedContext, precacheToneMapperShaderOnly, contextPriority);
+                                        enableProtectedContext, precacheToneMapperShaderOnly,
+                                        supportsBackgroundBlur, contextPriority);
     }
 
 private:
@@ -235,6 +243,7 @@
     bool useColorManagement = true;
     bool enableProtectedContext = false;
     bool precacheToneMapperShaderOnly = false;
+    bool supportsBackgroundBlur = false;
     RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
 };
 
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index ba5a3f5..e676740 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <chrono>
 #include <condition_variable>
 #include <fstream>
 
 #include <gtest/gtest.h>
+#include <cutils/properties.h>
 #include <renderengine/RenderEngine.h>
 #include <sync/sync.h>
 #include <ui/PixelFormat.h>
@@ -40,6 +45,7 @@
                     .setUseColorManagerment(false)
                     .setEnableProtectedContext(false)
                     .setPrecacheToneMapperShaderOnly(false)
+                    .setSupportsBackgroundBlur(true)
                     .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
         .build());
     }
@@ -324,6 +330,9 @@
     void fillBufferWithRoundedCorners();
 
     template <typename SourceVariant>
+    void fillBufferAndBlurBackground();
+
+    template <typename SourceVariant>
     void overlayCorners();
 
     void fillRedBufferTextureTransform();
@@ -702,6 +711,51 @@
 }
 
 template <typename SourceVariant>
+void RenderEngineTest::fillBufferAndBlurBackground() {
+        char value[PROPERTY_VALUE_MAX];
+    property_get("ro.surface_flinger.supports_background_blur", value, "0");
+    if (!atoi(value)) {
+        // This device doesn't support blurs, no-op.
+        return;
+    }
+
+    auto blurRadius = 50;
+    auto center = DEFAULT_DISPLAY_WIDTH / 2;
+
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings backgroundLayer;
+    backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this);
+    backgroundLayer.alpha = 1.0f;
+    layers.push_back(backgroundLayer);
+
+    renderengine::LayerSettings leftLayer;
+    leftLayer.geometry.boundaries =
+            Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect();
+    SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this);
+    leftLayer.alpha = 1.0f;
+    layers.push_back(leftLayer);
+
+    renderengine::LayerSettings blurLayer;
+    blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    blurLayer.backgroundBlurRadius = blurRadius;
+    blurLayer.alpha = 0;
+    layers.push_back(blurLayer);
+
+    invokeDraw(settings, layers, mBuffer);
+
+    expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
+                      50 /* tolerance */);
+    expectBufferColor(Rect(center, center - 5, center + 1, center + 5), 150, 150, 0, 255,
+                      50 /* tolerance */);
+}
+
+template <typename SourceVariant>
 void RenderEngineTest::overlayCorners() {
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1028,6 +1082,10 @@
     fillBufferWithRoundedCorners<ColorSourceVariant>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
+    fillBufferAndBlurBackground<ColorSourceVariant>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
     overlayCorners<ColorSourceVariant>();
 }
@@ -1080,6 +1138,10 @@
     fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+    fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
     overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
@@ -1132,6 +1194,10 @@
     fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
+    fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
     overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
@@ -1339,3 +1405,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 043f2ca..ba6255d 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -32,12 +32,6 @@
     sanitize: {
         integer_overflow: true,
         misc_undefined: ["bounds"],
-        diag: {
-            misc_undefined: ["bounds"],
-            no_recover: [
-                "bounds",
-            ],
-        },
     },
 
     srcs: [
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 04493f0..abc64bd 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -66,6 +66,7 @@
     "android.hardware.graphics.composer@2.1-command-buffer",
     "android.hardware.graphics.composer@2.2-command-buffer",
     "android.hardware.graphics.composer@2.3-command-buffer",
+    "android.hardware.graphics.composer@2.4-command-buffer",
     "libdvr_headers",
     "libsurfaceflinger_headers",
 ]
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 51878e9..e19802b 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -25,6 +25,7 @@
 #include <dlfcn.h>
 
 #include <android/dlext.h>
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <utils/Timers.h>
 
@@ -205,7 +206,6 @@
     }
 
     cnx->systemDriverUnloaded = true;
-    cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
 }
 
 void* Loader::open(egl_connection_t* cnx)
@@ -228,7 +228,6 @@
     } else {
         cnx->shouldUseAngle = false;
     }
-    cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
 
     // Firstly, try to load ANGLE driver.
     driver_t* hnd = attempt_to_load_angle(cnx);
@@ -238,7 +237,6 @@
     }
 
     bool failToLoadFromDriverSuffixProperty = false;
-    cnx->systemDriverUseExactName = true;
     if (!hnd) {
         // If updated driver apk is set but fail to load, abort here.
         if (android::GraphicsEnv::getInstance().getDriverNamespace()) {
@@ -250,19 +248,16 @@
         // 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, cnx->systemDriverProperty, nullptr) <= 0) {
+            if (property_get(key, prop, nullptr) <= 0) {
                 continue;
             }
-            hnd = attempt_to_load_system_driver(cnx, cnx->systemDriverProperty,
-                                                cnx->systemDriverUseExactName);
+            hnd = attempt_to_load_system_driver(cnx, prop, true);
             if (hnd) {
-                cnx->systemDriverUseProperty = true;
                 break;
-            } else {
-                if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
-                    failToLoadFromDriverSuffixProperty = true;
-                }
+            } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+                failToLoadFromDriverSuffixProperty = true;
             }
         }
     }
@@ -273,12 +268,11 @@
         // i.e.:
         //      libGLES.so, or:
         //      libEGL.so, libGLESv1_CM.so, libGLESv2.so
-        hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
+        hnd = attempt_to_load_system_driver(cnx, nullptr, true);
     }
 
     if (!hnd && !failToLoadFromDriverSuffixProperty) {
-        cnx->systemDriverUseExactName = false;
-        hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
+        hnd = attempt_to_load_system_driver(cnx, nullptr, false);
     }
 
     if (!hnd) {
@@ -293,11 +287,14 @@
     if (!cnx->libEgl) {
         cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
     }
+    if (!cnx->libGles1) {
+        cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+    }
     if (!cnx->libGles2) {
         cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
     }
 
-    if (!cnx->libEgl || !cnx->libGles2) {
+    if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
         android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
                                                             false, systemTime() - openTime);
     }
@@ -305,7 +302,8 @@
     LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
             "couldn't load system EGL wrapper libraries");
 
-    LOG_ALWAYS_FATAL_IF(!cnx->libGles2, "couldn't load system OpenGL ESv2+ wrapper libraries");
+    LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
+                        "couldn't load system OpenGL ES wrapper libraries");
 
     android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true,
                                                         systemTime() - openTime);
@@ -321,7 +319,7 @@
 
     cnx->shouldUseAngle = false;
     cnx->angleDecided = false;
-    cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
+    cnx->useAngle = false;
 
     if (cnx->vendorEGL) {
         dlclose(cnx->vendorEGL);
@@ -526,6 +524,7 @@
     if (so) {
         ALOGV("Loaded ANGLE %s library for '%s' (instead of native)", kind,
             android::GraphicsEnv::getInstance().getAngleAppName().c_str());
+        cnx->useAngle = true;
 
         char prop[PROPERTY_VALUE_MAX];
 
@@ -568,6 +567,7 @@
     } else {
         ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
             android::GraphicsEnv::getInstance().getAngleAppName().c_str());
+        cnx->useAngle = false;
     }
     cnx->angleDecided = true;
 
@@ -597,7 +597,6 @@
 
 Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
     ATRACE_CALL();
-    assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (!ns) {
         return nullptr;
@@ -612,17 +611,19 @@
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
+        dso = load_angle("GLESv1_CM", ns, cnx);
+        initialize_api(dso, cnx, GLESv1_CM);
+        hnd->set(dso, GLESv1_CM);
+
         dso = load_angle("GLESv2", ns, cnx);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
-        cnx->loadedDriverType = egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER;
     }
     return hnd;
 }
 
 Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
     ATRACE_CALL();
-    assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
 #ifndef __ANDROID_VNDK__
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
     if (!ns) {
@@ -634,9 +635,8 @@
     driver_t* hnd = nullptr;
     void* dso = load_updated_driver("GLES", ns);
     if (dso) {
-        initialize_api(dso, cnx, EGL | GLESv2);
+        initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
         hnd = new driver_t(dso);
-        if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_COMBO_DRIVER;
         return hnd;
     }
 
@@ -645,10 +645,13 @@
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
+        dso = load_updated_driver("GLESv1_CM", ns);
+        initialize_api(dso, cnx, GLESv1_CM);
+        hnd->set(dso, GLESv1_CM);
+
         dso = load_updated_driver("GLESv2", ns);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
-        cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER;
     }
     return hnd;
 #else
@@ -659,94 +662,30 @@
 Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
                                                         const bool exact) {
     ATRACE_CALL();
-    assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
     android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
     driver_t* hnd = nullptr;
     void* dso = load_system_driver("GLES", suffix, exact);
     if (dso) {
-        initialize_api(dso, cnx, EGL | GLESv2);
+        initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
         hnd = new driver_t(dso);
-        if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_COMBO_DRIVER;
         return hnd;
     }
-
     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, exact);
+        initialize_api(dso, cnx, GLESv1_CM);
+        hnd->set(dso, GLESv1_CM);
+
         dso = load_system_driver("GLESv2", suffix, exact);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
-        cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER;
     }
     return hnd;
 }
 
-bool Loader::load_glesv1_driver(egl_connection_t* cnx) {
-    ATRACE_CALL();
-    void* dso = nullptr;
-
-    driver_t* hnd = (driver_t*)cnx->dso;
-    // EGL driver must have been loaded. if not, something went wrong.
-    if (!hnd || cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER) {
-        return false;
-    }
-
-    if (cnx->libGles1) return EGL_TRUE;
-
-    // If there is a GLES driver, use that first
-    switch (cnx->loadedDriverType) {
-        case egl_connection_t::GLES_SYSTEM_COMBO_DRIVER:
-        case egl_connection_t::GLES_UPDATED_COMBO_DRIVER: {
-            dso = hnd->dso[0];
-            initialize_api(dso, cnx, GLESv1_CM);
-            break;
-        }
-        case egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER: {
-            android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
-            dso = load_angle("GLESv1_CM", ns, cnx);
-            if (dso) {
-                initialize_api(dso, cnx, GLESv1_CM);
-                hnd->set(dso, GLESv1_CM);
-            }
-            break;
-        }
-        case egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER: {
-            android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
-            void* dso = load_updated_driver("GLESv1_CM", ns);
-            if (dso) {
-                initialize_api(dso, cnx, GLESv1_CM);
-                hnd->set(dso, GLESv1_CM);
-            }
-            break;
-        }
-        case egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER: {
-            dso = load_system_driver("GLESv1_CM",
-                                     cnx->systemDriverUseProperty ? cnx->systemDriverProperty
-                                                                  : nullptr,
-                                     cnx->systemDriverUseExactName);
-            if (dso) {
-                initialize_api(dso, cnx, GLESv1_CM);
-                hnd->set(dso, GLESv1_CM);
-            }
-            break;
-        }
-        default: {
-            ALOGE("Bad loadedDriverType (%d)", cnx->loadedDriverType);
-            break;
-        }
-    }
-
-    if (!cnx->libGles1) {
-        cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
-    }
-
-    LOG_ALWAYS_FATAL_IF(!cnx->libGles1, "couldn't load system OpenGL ES V1 wrapper libraries");
-
-    return dso ? true : false;
-}
-
 void Loader::initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask) {
     if (mask & EGL) {
         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 4199753..6f31ab4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -53,8 +53,6 @@
     void* open(egl_connection_t* cnx);
     void close(egl_connection_t* cnx);
 
-    bool load_glesv1_driver(egl_connection_t* cnx);
-
 private:
     Loader();
     driver_t* attempt_to_load_angle(egl_connection_t* cnx);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 768d3b5..0581708 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -172,10 +172,6 @@
 
 // ----------------------------------------------------------------------------
 
-// this mutex protects:
-//    d->disp[]
-//    egl_init_drivers_locked()
-//
 static EGLBoolean egl_init_drivers_locked() {
     if (sEarlyInitState) {
         // initialized by static ctor. should be set here.
@@ -202,15 +198,9 @@
     return cnx->dso ? EGL_TRUE : EGL_FALSE;
 }
 
-static EGLBoolean egl_init_glesv1_drivers_locked() {
-    // get our driver loader
-    Loader& loader(Loader::getInstance());
 
-    // dynamically load our GLESV1 implementation
-    egl_connection_t* cnx = &gEGLImpl;
-    return loader.load_glesv1_driver(cnx);
-}
-
+// this mutex protects driver load logic as a critical section since it accesses to global variable
+// like gEGLImpl
 static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
 
 EGLBoolean egl_init_drivers() {
@@ -221,14 +211,6 @@
     return res;
 }
 
-EGLBoolean egl_init_glesv1_drivers() {
-    EGLBoolean res;
-    pthread_mutex_lock(&sInitDriverMutex);
-    res = egl_init_glesv1_drivers_locked();
-    pthread_mutex_unlock(&sInitDriverMutex);
-    return res;
-}
-
 static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
 static std::chrono::steady_clock::time_point sLogPrintTime;
 static constexpr std::chrono::seconds DURATION(1);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 3b19b32..67d69b4 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -220,7 +220,7 @@
     if (cnx->dso) {
         EGLDisplay dpy = EGL_NO_DISPLAY;
 
-        if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
+        if (cnx->useAngle) {
             EGLint error;
             dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
             if (error != EGL_NONE) {
@@ -464,7 +464,7 @@
         egl_connection_t* const cnx = &gEGLImpl;
         if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
             // If we're using ANGLE reset any custom DisplayPlatform
-            if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
+            if (cnx->useAngle) {
                 angle::resetAnglePlatform(disp.dpy);
             }
             if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index e2bc5c6..c8840f9 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -277,7 +277,6 @@
 
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 extern EGLBoolean egl_init_drivers();
-extern EGLBoolean egl_init_glesv1_drivers();
 extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
 extern gl_hooks_t gHooksTrace;
 
@@ -957,42 +956,41 @@
             egl_context_t* const c = get_context(share_list);
             share_list = c->context;
         }
-
-        // figure out if it's a GLESv1 or GLESv2
-        int gles_version_idx = egl_connection_t::GLESv1_INDEX;
-        if (attrib_list) {
-            const EGLint* ptr = attrib_list; // so that we don't modify attrib_list
-            while (*ptr != EGL_NONE) {
-                GLint attr = *ptr++;
-                GLint value = *ptr++;
-                if (attr == EGL_CONTEXT_CLIENT_VERSION) {
-                    if (value == 1) {
-                        gles_version_idx = egl_connection_t::GLESv1_INDEX;
-                    } else if (value == 2 || value == 3) {
-                        gles_version_idx = egl_connection_t::GLESv2_INDEX;
-                    }
-                } else if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR &&
-                           cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0)) {
-                    // b/111083885 - If we are presenting EGL 1.4 interface to apps
-                    // error out on robust access attributes that are invalid
-                    // in EGL 1.4 as the driver may be fine with them but dEQP expects
-                    // tests to fail according to spec.
+        // b/111083885 - If we are presenting EGL 1.4 interface to apps
+        // error out on robust access attributes that are invalid
+        // in EGL 1.4 as the driver may be fine with them but dEQP expects
+        // tests to fail according to spec.
+        if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
+            const EGLint* attrib_ptr = attrib_list;
+            while (*attrib_ptr != EGL_NONE) {
+                GLint attr = *attrib_ptr++;
+                GLint value = *attrib_ptr++;
+                if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
+                    // We are GL ES context with EGL 1.4, this is an invalid
+                    // attribute
                     return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
                 }
-            }
+            };
         }
-
-        // GLESV1 driver is lazily loaded and initialized
-        if (gles_version_idx == egl_connection_t::GLESv1_INDEX) {
-            android::GraphicsEnv::getInstance().setTargetStats(
-                    android::GpuStatsInfo::Stats::GLES_1_IN_USE);
-            if (!egl_init_glesv1_drivers()) return EGL_NO_CONTEXT;
-        }
-
         EGLContext context = cnx->egl.eglCreateContext(
                 dp->disp.dpy, config, share_list, attrib_list);
         if (context != EGL_NO_CONTEXT) {
-            egl_context_t* c = new egl_context_t(dpy, context, config, cnx, gles_version_idx);
+            // figure out if it's a GLESv1 or GLESv2
+            int version = egl_connection_t::GLESv1_INDEX;
+            if (attrib_list) {
+                while (*attrib_list != EGL_NONE) {
+                    GLint attr = *attrib_list++;
+                    GLint value = *attrib_list++;
+                    if (attr == EGL_CONTEXT_CLIENT_VERSION && (value == 2 || value == 3)) {
+                        version = egl_connection_t::GLESv2_INDEX;
+                    }
+                };
+            }
+            if (version == egl_connection_t::GLESv1_INDEX) {
+                android::GraphicsEnv::getInstance().setTargetStats(
+                        android::GpuStatsInfo::Stats::GLES_1_IN_USE);
+            }
+            egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
             return c;
         }
     }
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 4e9d7d0..7bb9b59 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -17,12 +17,11 @@
 #ifndef ANDROID_EGLDEFS_H
 #define ANDROID_EGLDEFS_H
 
-#include <cutils/properties.h>
-#include <log/log.h>
-
 #include "../hooks.h"
 #include "egl_platform_entries.h"
 
+#include <log/log.h>
+
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 4
 #define EGL_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
@@ -45,15 +44,6 @@
         GLESv2_INDEX = 1
     };
 
-    enum {
-        GLES_NO_DRIVER = 0, // no driver is loaded
-        GLES_SYSTEM_COMBO_DRIVER = 1, // GLES combo driver in system folder is loaded
-        GLES_SYSTEM_STANDALONE_DRIVER = 2, // standalone system drivers are loaded
-        GLES_ANGLE_STANDALONE_DRIVER = 3, // ANGLE (always standalone) drivers are loaded.
-        GLES_UPDATED_COMBO_DRIVER = 4, // GLES combo driver in updated driver folder is loaded
-        GLES_UPDATED_STANDALONE_DRIVER = 5, // standalone drivers in updated driver folder are loaded
-    };
-
     inline egl_connection_t() : dso(nullptr),
                                 libEgl(nullptr),
                                 libGles1(nullptr),
@@ -93,12 +83,9 @@
     bool                systemDriverUnloaded;
     bool                shouldUseAngle; // Should we attempt to load ANGLE
     bool                angleDecided;   // Have we tried to load ANGLE
+    bool                useAngle;       // Was ANGLE successfully loaded
     EGLint              angleBackend;
-    int                 loadedDriverType;
     void*               vendorEGL;
-    bool                systemDriverUseExactName;
-    bool                systemDriverUseProperty;
-    char                systemDriverProperty[PROPERTY_VALUE_MAX + 1];
 };
 // clang-format on
 
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
new file mode 100644
index 0000000..5a5dc89
--- /dev/null
+++ b/services/automotive/display/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.frameworks.automotive.display@1.0-service",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "main_automotivedisplay.cpp",
+        "CarWindowService.cpp",
+    ],
+    init_rc: ["android.frameworks.automotive.display@1.0-service.rc"],
+
+    shared_libs: [
+        "android.frameworks.automotive.display@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "libgui",
+        "libhidlbase",
+        "liblog",
+        "libui",
+        "libutils",
+    ],
+
+    local_include_dirs: [
+        "include",
+    ],
+}
diff --git a/services/automotive/display/CarWindowService.cpp b/services/automotive/display/CarWindowService.cpp
new file mode 100644
index 0000000..e95c9e1
--- /dev/null
+++ b/services/automotive/display/CarWindowService.cpp
@@ -0,0 +1,121 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include <ui/DisplayInfo.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+
+#include "CarWindowService.h"
+
+namespace android {
+namespace frameworks {
+namespace automotive {
+namespace display {
+namespace V1_0 {
+namespace implementation {
+
+Return<sp<IGraphicBufferProducer>>
+    CarWindowService::getIGraphicBufferProducer() {
+    if (mSurface == nullptr) {
+        status_t err;
+        mSurfaceComposerClient = new SurfaceComposerClient();
+
+        err = mSurfaceComposerClient->initCheck();
+        if (err != NO_ERROR) {
+            ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
+            mSurfaceComposerClient = nullptr;
+            return nullptr;
+        }
+
+        // Get main display parameters.
+        sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
+        if (mainDpy == nullptr) {
+            ALOGE("Failed to get internal display ");
+            return nullptr;
+        }
+        DisplayInfo mainDpyInfo;
+        err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+        if (err != NO_ERROR) {
+            ALOGE("Failed to get display characteristics");
+            return nullptr;
+        }
+        unsigned int mWidth, mHeight;
+        if (mainDpyInfo.orientation != ui::ROTATION_0 &&
+            mainDpyInfo.orientation != ui::ROTATION_180) {
+            // rotated
+            mWidth = mainDpyInfo.h;
+            mHeight = mainDpyInfo.w;
+        } else {
+            mWidth = mainDpyInfo.w;
+            mHeight = mainDpyInfo.h;
+        }
+
+        mSurfaceControl = mSurfaceComposerClient->createSurface(
+                String8("Automotive Display"), mWidth, mHeight,
+                PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
+        if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) {
+            ALOGE("Failed to create SurfaceControl");
+            mSurfaceComposerClient = nullptr;
+            mSurfaceControl = nullptr;
+            return nullptr;
+        }
+
+        // SurfaceControl::getSurface is guaranteed to be not null.
+        mSurface = mSurfaceControl->getSurface();
+    }
+
+    return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
+                    B2HGraphicBufferProducer(
+                        mSurface->getIGraphicBufferProducer());
+}
+
+Return<bool> CarWindowService::showWindow() {
+    status_t status = NO_ERROR;
+
+    if (mSurfaceControl != nullptr) {
+        status = SurfaceComposerClient::Transaction{}
+                         .setLayer(
+                             mSurfaceControl, 0x7FFFFFFF) // always on top
+                         .show(mSurfaceControl)
+                         .apply();
+    } else {
+        ALOGE("showWindow: Failed to get a valid SurfaceControl!");
+        return false;
+    }
+
+    return status == NO_ERROR;
+}
+
+Return<bool> CarWindowService::hideWindow() {
+    status_t status = NO_ERROR;
+
+    if (mSurfaceControl != nullptr) {
+        status = SurfaceComposerClient::Transaction{}
+                        .hide(mSurfaceControl)
+                        .apply();
+    } else {
+        ALOGE("hideWindow: Failed to get a valid SurfaceControl!");
+        return false;
+    }
+
+    return status == NO_ERROR;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace display
+}  // namespace automotive
+}  // namespace frameworks
+}  // namespace android
+
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
new file mode 100644
index 0000000..ffb7b5e
--- /dev/null
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -0,0 +1,5 @@
+service automotive_display /system/bin/android.frameworks.automotive.display@1.0-service
+    class hal
+    user graphics
+    group automotive_evs
+    disabled  # will not automatically start with its class; must be explicitly started.
diff --git a/services/automotive/display/include/CarWindowService.h b/services/automotive/display/include/CarWindowService.h
new file mode 100644
index 0000000..3290cc7
--- /dev/null
+++ b/services/automotive/display/include/CarWindowService.h
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#pragma once
+
+#include <android/frameworks/automotive/display/1.0/ICarWindowService.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+namespace android {
+namespace frameworks {
+namespace automotive {
+namespace display {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::sp;
+using ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
+
+class CarWindowService : public ICarWindowService {
+public:
+    Return<sp<IGraphicBufferProducer>> getIGraphicBufferProducer() override;
+    Return<bool> showWindow() override;
+    Return<bool> hideWindow() override;
+
+private:
+    sp<android::Surface> mSurface;
+    sp<android::SurfaceComposerClient> mSurfaceComposerClient;
+    sp<android::SurfaceControl> mSurfaceControl;
+};
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace display
+}  // namespace automotive
+}  // namespace frameworks
+}  // namespace android
+
diff --git a/services/automotive/display/main_automotivedisplay.cpp b/services/automotive/display/main_automotivedisplay.cpp
new file mode 100644
index 0000000..69f0a13
--- /dev/null
+++ b/services/automotive/display/main_automotivedisplay.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AutomotiveDisplayService"
+
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "CarWindowService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::frameworks::automotive::display::V1_0::ICarWindowService;
+
+// The namespace in which all our implementation code lives
+using namespace android::frameworks::automotive::display::V1_0::implementation;
+using namespace android;
+
+const static char kServiceName[] = "default";
+
+int main() {
+    ALOGI("Car Window Service is starting");
+
+    android::sp<ICarWindowService> service = new CarWindowService();
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    status_t status = service->registerAsService(kServiceName);
+    if (status == OK) {
+        ALOGD("%s is ready.", kServiceName);
+        joinRpcThreadpool();
+    } else {
+        ALOGE("Could not register service %s (%d).", kServiceName, status);
+    }
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("Car Window Service is shutting down");
+
+    return 1;
+}
+
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index e925f5b..b723654 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -111,6 +111,21 @@
     msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags);
 }
 
+// --- FocusEntry ---
+
+// Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries
+FocusEntry::FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp<IBinder> connectionToken,
+                       bool hasFocus)
+      : EventEntry(sequenceNum, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER),
+        connectionToken(connectionToken),
+        hasFocus(hasFocus) {}
+
+FocusEntry::~FocusEntry() {}
+
+void FocusEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("FocusEvent(hasFocus=%s)", hasFocus ? "true" : "false");
+}
+
 // --- KeyEntry ---
 
 KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 9dcaadc..e8c37f0 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -33,7 +33,13 @@
 constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
 
 struct EventEntry {
-    enum class Type { CONFIGURATION_CHANGED, DEVICE_RESET, KEY, MOTION };
+    enum class Type {
+        CONFIGURATION_CHANGED,
+        DEVICE_RESET,
+        FOCUS,
+        KEY,
+        MOTION,
+    };
 
     static const char* typeToString(Type type) {
         switch (type) {
@@ -41,6 +47,8 @@
                 return "CONFIGURATION_CHANGED";
             case Type::DEVICE_RESET:
                 return "DEVICE_RESET";
+            case Type::FOCUS:
+                return "FOCUS";
             case Type::KEY:
                 return "KEY";
             case Type::MOTION:
@@ -102,6 +110,17 @@
     virtual ~DeviceResetEntry();
 };
 
+struct FocusEntry : EventEntry {
+    sp<IBinder> connectionToken;
+    bool hasFocus;
+
+    FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus);
+    virtual void appendDescription(std::string& msg) const;
+
+protected:
+    virtual ~FocusEntry();
+};
+
 struct KeyEntry : EventEntry {
     int32_t deviceId;
     uint32_t source;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6157d99..30fdf90 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -270,7 +270,7 @@
     ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
     const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
 
-    PointerCoords pointerCoords[MAX_POINTERS];
+    PointerCoords pointerCoords[motionEntry.pointerCount];
 
     // Use the first pointer information to normalize all other pointers. This could be any pointer
     // as long as all other pointers are normalized to the same value and the final DispatchEntry
@@ -310,11 +310,19 @@
                             motionEntry.pointerProperties, pointerCoords, 0 /* xOffset */,
                             0 /* yOffset */);
 
-    return std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
-                                           inputTargetFlags, firstPointerInfo.xOffset,
-                                           firstPointerInfo.yOffset, inputTarget.globalScaleFactor,
-                                           firstPointerInfo.windowXScale,
-                                           firstPointerInfo.windowYScale);
+    if (motionEntry.injectionState) {
+        combinedMotionEntry->injectionState = motionEntry.injectionState;
+        combinedMotionEntry->injectionState->refCount += 1;
+    }
+
+    std::unique_ptr<DispatchEntry> dispatchEntry =
+            std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
+                                            inputTargetFlags, firstPointerInfo.xOffset,
+                                            firstPointerInfo.yOffset, inputTarget.globalScaleFactor,
+                                            firstPointerInfo.windowXScale,
+                                            firstPointerInfo.windowYScale);
+    combinedMotionEntry->release();
+    return dispatchEntry;
 }
 
 // --- InputDispatcherThread ---
@@ -530,6 +538,14 @@
             break;
         }
 
+        case EventEntry::Type::FOCUS: {
+            FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
+            dispatchFocusLocked(currentTime, typedEntry);
+            done = true;
+            dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
+            break;
+        }
+
         case EventEntry::Type::KEY: {
             KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
             if (isAppSwitchDue) {
@@ -634,7 +650,8 @@
             break;
         }
         case EventEntry::Type::CONFIGURATION_CHANGED:
-        case EventEntry::Type::DEVICE_RESET: {
+        case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::FOCUS: {
             // nothing to do
             break;
         }
@@ -773,6 +790,7 @@
             }
             break;
         }
+        case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             LOG_ALWAYS_FATAL("Should not drop %s events", EventEntry::typeToString(entry.type));
@@ -933,6 +951,25 @@
     return true;
 }
 
+void InputDispatcher::enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) {
+    FocusEntry* focusEntry =
+            new FocusEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, now(), window.getToken(), hasFocus);
+    enqueueInboundEventLocked(focusEntry);
+}
+
+void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) {
+    sp<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
+    if (channel == nullptr) {
+        return; // Window has gone away
+    }
+    InputTarget target;
+    target.inputChannel = channel;
+    target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+    entry->dispatchInProgress = true;
+
+    dispatchEventLocked(currentTime, entry, {target});
+}
+
 bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
                                         DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Preprocessing.
@@ -1315,6 +1352,7 @@
             displayId = motionEntry.displayId;
             break;
         }
+        case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             ALOGE("%s events do not have a target display", EventEntry::typeToString(entry.type));
@@ -2062,6 +2100,10 @@
 }
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
+    if (eventEntry.type == EventEntry::Type::FOCUS) {
+        // Focus events are passed to apps, but do not represent user activity.
+        return;
+    }
     int32_t displayId = getTargetDisplayId(eventEntry);
     sp<InputWindowHandle> focusedWindowHandle =
             getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
@@ -2096,6 +2138,7 @@
             eventType = USER_ACTIVITY_EVENT_BUTTON;
             break;
         }
+        case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             LOG_ALWAYS_FATAL("%s events are not user activity",
@@ -2292,6 +2335,9 @@
 
             break;
         }
+        case EventEntry::Type::FOCUS: {
+            break;
+        }
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             LOG_ALWAYS_FATAL("%s events should not go to apps",
@@ -2427,6 +2473,14 @@
                 reportTouchEventForStatistics(*motionEntry);
                 break;
             }
+            case EventEntry::Type::FOCUS: {
+                FocusEntry* focusEntry = static_cast<FocusEntry*>(eventEntry);
+                status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
+                                                                      focusEntry->hasFocus,
+                                                                      mInTouchMode);
+                break;
+            }
+
             case EventEntry::Type::CONFIGURATION_CHANGED:
             case EventEntry::Type::DEVICE_RESET: {
                 LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
@@ -2666,6 +2720,10 @@
                                                      *cancelationEventEntry));
                     break;
                 }
+                case EventEntry::Type::FOCUS: {
+                    LOG_ALWAYS_FATAL("Canceling focus events is not supported");
+                    break;
+                }
                 case EventEntry::Type::CONFIGURATION_CHANGED:
                 case EventEntry::Type::DEVICE_RESET: {
                     LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
@@ -3456,6 +3514,7 @@
                     CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                                                "focus left window");
                     synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options);
+                    enqueueFocusEventLocked(*oldFocusedWindowHandle, false /*hasFocus*/);
                 }
                 mFocusedWindowHandlesByDisplay.erase(displayId);
             }
@@ -3465,6 +3524,7 @@
                           newFocusedWindowHandle->getName().c_str(), displayId);
                 }
                 mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
+                enqueueFocusEventLocked(*newFocusedWindowHandle, true /*hasFocus*/);
             }
 
             if (mFocusedDisplayId == displayId) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 50b5250..a4ba0de 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -157,6 +157,9 @@
     // Cleans up input state when dropping an inbound event.
     void dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) REQUIRES(mLock);
 
+    // Enqueues a focus event.
+    void enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) REQUIRES(mLock);
+
     // Adds an event to a queue of recent events for debugging purposes.
     void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
 
@@ -299,6 +302,7 @@
                            nsecs_t* nextWakeupTime) REQUIRES(mLock);
     bool dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason,
                               nsecs_t* nextWakeupTime) REQUIRES(mLock);
+    void dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) REQUIRES(mLock);
     void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
                              const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
 
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index c567c8b..f42ddcf 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -209,6 +209,8 @@
                 return AMOTION_EVENT_TOOL_TYPE_FINGER;
             case MT_TOOL_PEN:
                 return AMOTION_EVENT_TOOL_TYPE_STYLUS;
+            case MT_TOOL_PALM:
+                return AMOTION_EVENT_TOOL_TYPE_PALM;
         }
     }
     return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
@@ -247,6 +249,14 @@
             continue;
         }
 
+        if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
+            if (!mCurrentMotionAborted) {
+                ALOGI("Canceling touch gesture from device %s because the palm event was detected",
+                      getDeviceName().c_str());
+                cancelTouch(when);
+            }
+        }
+
         if (outCount >= MAX_POINTERS) {
 #if DEBUG_POINTERS
             ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index bd8d2a4..98ebf50 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -482,12 +482,31 @@
                 EXPECT_EQ(expectedFlags, motionEvent.getFlags());
                 break;
             }
+            case AINPUT_EVENT_TYPE_FOCUS: {
+                FAIL() << "Use 'consumeFocusEvent' for FOCUS events";
+            }
             default: {
                 FAIL() << mName.c_str() << ": invalid event type: " << expectedEventType;
             }
         }
     }
 
+    void consumeFocusEvent(bool hasFocus, bool inTouchMode) {
+        InputEvent* event = consume();
+        ASSERT_NE(nullptr, event) << mName.c_str()
+                                  << ": consumer should have returned non-NULL event.";
+        ASSERT_EQ(AINPUT_EVENT_TYPE_FOCUS, event->getType())
+                << "Got " << inputEventTypeToString(event->getType())
+                << " event instead of FOCUS event";
+
+        ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
+                << mName.c_str() << ": event displayId should always be NONE.";
+
+        FocusEvent* focusEvent = static_cast<FocusEvent*>(event);
+        EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
+        EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode());
+    }
+
     void assertNoEvents() {
         InputEvent* event = consume();
         ASSERT_EQ(nullptr, event)
@@ -508,7 +527,6 @@
 public:
     static const int32_t WIDTH = 600;
     static const int32_t HEIGHT = 800;
-    const std::string mName;
 
     FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
                      const sp<InputDispatcher>& dispatcher, const std::string name,
@@ -551,7 +569,7 @@
 
     virtual bool updateInfo() { return true; }
 
-    void setFocus() { mInfo.hasFocus = true; }
+    void setFocus(bool hasFocus) { mInfo.hasFocus = hasFocus; }
 
     void setFrame(const Rect& frame) {
         mInfo.frameLeft = frame.left;
@@ -586,6 +604,12 @@
                      expectedFlags);
     }
 
+    void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) {
+        ASSERT_NE(mInputReceiver, nullptr)
+                << "Cannot consume events from a window with no receiver";
+        mInputReceiver->consumeFocusEvent(hasFocus, inTouchMode);
+    }
+
     void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
                       int32_t expectedFlags) {
         ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
@@ -608,7 +632,10 @@
 
     sp<IBinder> getToken() { return mInfo.token; }
 
+    const std::string& getName() { return mName; }
+
 private:
+    const std::string mName;
     std::unique_ptr<FakeInputReceiver> mInputReceiver;
 };
 
@@ -759,10 +786,11 @@
     // Set focused application.
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
-    // Expect one focus window exist in display.
-    windowSecond->setFocus();
-
+    // Display should have only one focused window
+    windowSecond->setFocus(true);
     mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT);
+
+    windowSecond->consumeFocusEvent(true);
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
             << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
 
@@ -782,10 +810,11 @@
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
-    windowTop->setFocus();
-    windowSecond->setFocus();
+    windowTop->setFocus(true);
+    windowSecond->setFocus(true);
 
     mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT);
+    windowTop->consumeFocusEvent(true);
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
             << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
 
@@ -805,11 +834,12 @@
     // Set focused application.
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
-    windowTop->setFocus();
-    windowSecond->setFocus();
+    windowTop->setFocus(true);
+    windowSecond->setFocus(true);
     // Release channel for window is no longer valid.
     windowTop->releaseChannel();
     mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT);
+    windowSecond->consumeFocusEvent(true);
 
     // Test inject a key down, should dispatch to a valid window.
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
@@ -849,9 +879,10 @@
     sp<FakeApplicationHandle> application = new FakeApplicationHandle();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
-    window->setFocus();
+    window->setFocus(true);
 
     mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(true);
 
     NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
     mDispatcher->notifyKey(&keyArgs);
@@ -890,6 +921,59 @@
                          0 /*expectedFlags*/);
 }
 
+TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+    window->setFocus(true);
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+    window->consumeFocusEvent(true);
+
+    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyKey(&keyArgs);
+
+    // Window should receive key down event.
+    window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+}
+
+TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyKey(&keyArgs);
+    mDispatcher->waitForIdle();
+
+    window->assertNoEvents();
+}
+
+// If a window is touchable, but does not have focus, it should receive motion events, but not keys
+TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+    // Send key
+    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyKey(&keyArgs);
+    // Send motion
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // Window should receive only the motion event
+    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+    window->assertNoEvents(); // Key event or focus event will not be received
+}
+
 class FakeMonitorReceiver {
 public:
     FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
@@ -946,9 +1030,10 @@
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-    window->setFocus();
+    window->setFocus(true);
 
     mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(true);
 
     FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
                                                       true /*isGestureMonitor*/);
@@ -1010,6 +1095,49 @@
                          0 /*expectedFlags*/);
 }
 
+/**
+ * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
+ * the device default right away. In the test scenario, we check both the default value,
+ * and the action of enabling / disabling.
+ */
+TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+
+    // Set focused application.
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+    window->setFocus(true);
+
+    SCOPED_TRACE("Check default value of touch mode");
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+    SCOPED_TRACE("Remove the window to trigger focus loss");
+    window->setFocus(false);
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(false /*hasFocus*/, true /*inTouchMode*/);
+
+    SCOPED_TRACE("Disable touch mode");
+    mDispatcher->setInTouchMode(false);
+    window->setFocus(true);
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(true /*hasFocus*/, false /*inTouchMode*/);
+
+    SCOPED_TRACE("Remove the window to trigger focus loss");
+    window->setFocus(false);
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(false /*hasFocus*/, false /*inTouchMode*/);
+
+    SCOPED_TRACE("Enable touch mode again");
+    mDispatcher->setInTouchMode(true);
+    window->setFocus(true);
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+    window->assertNoEvents();
+}
+
 /* Test InputDispatcher for MultiDisplay */
 class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
 public:
@@ -1023,8 +1151,9 @@
 
         // Set focus window for primary display, but focused display would be second one.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
-        windowInPrimary->setFocus();
+        windowInPrimary->setFocus(true);
         mDispatcher->setInputWindows({windowInPrimary}, ADISPLAY_ID_DEFAULT);
+        windowInPrimary->consumeFocusEvent(true);
 
         application2 = new FakeApplicationHandle();
         windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
@@ -1034,8 +1163,9 @@
         mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
         // Set focus window for second display.
         mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
-        windowInSecondary->setFocus();
+        windowInSecondary->setFocus(true);
         mDispatcher->setInputWindows({windowInSecondary}, SECOND_DISPLAY_ID);
+        windowInSecondary->consumeFocusEvent(true);
     }
 
     virtual void TearDown() override {
@@ -1094,6 +1224,7 @@
     ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
             << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
     windowInPrimary->assertNoEvents();
+    windowInSecondary->consumeFocusEvent(false);
     windowInSecondary->assertNoEvents();
 }
 
@@ -1244,10 +1375,11 @@
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-        mFocusedWindow->setFocus();
+        mFocusedWindow->setFocus(true);
 
         // Expect one focus window exist in display.
         mDispatcher->setInputWindows({mUnfocusedWindow, mFocusedWindow}, ADISPLAY_ID_DEFAULT);
+        mFocusedWindow->consumeFocusEvent(true);
     }
 
     virtual void TearDown() override {
@@ -1350,7 +1482,7 @@
 
     void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
                             const std::vector<PointF>& points) {
-        std::string name = window->mName;
+        const std::string name = window->getName();
         InputEvent* event = window->consume();
 
         ASSERT_NE(nullptr, event) << name.c_str()
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 1fc8217..a9d7793 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6798,4 +6798,95 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 }
 
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    addMapperAndConfigure(mapper);
+
+    NotifyMotionArgs motionArgs;
+
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+    // finger down
+    processId(mapper, 1);
+    processPosition(mapper, x1, y1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // finger move
+    processId(mapper, 1);
+    processPosition(mapper, x2, y2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // finger up.
+    processId(mapper, -1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // new finger down
+    processId(mapper, 1);
+    processPosition(mapper, x3, y3);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+}
+
+/**
+ * Test touch should be canceled when received the MT_TOOL_PALM event, and the following MOVE and
+ * UP events should be ignored.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    addMapperAndConfigure(mapper);
+
+    NotifyMotionArgs motionArgs;
+
+    // default tool type is finger
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+    processId(mapper, 1);
+    processPosition(mapper, x1, y1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // Tool changed to MT_TOOL_PALM expect sending the cancel event.
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+    // Ignore the following MOVE and UP events if had detect a palm event.
+    processId(mapper, 1);
+    processPosition(mapper, x2, y2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // finger up.
+    processId(mapper, -1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // new finger down
+    processToolType(mapper, MT_TOOL_FINGER);
+    processId(mapper, 1);
+    processPosition(mapper, x3, y3);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index d476f7b4..9a7eabd 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -7,6 +7,7 @@
         "-Wthread-safety",
         "-Wunused",
         "-Wunreachable-code",
+        "-Wconversion",
     ],
 }
 
@@ -51,7 +52,7 @@
         "libprocessgroup",
         "libprotobuf-cpp-lite",
         "libsync",
-        "libtimestats_proto",
+        "libtimestats",
         "libui",
         "libinput",
         "libutils",
@@ -70,7 +71,6 @@
         "libperfetto_client_experimental",
         "librenderengine",
         "libserviceutils",
-        "libtimestats",
         "libtrace_proto",
         "libvr_manager",
         "libvrflinger",
@@ -79,12 +79,12 @@
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
         "android.hardware.graphics.composer@2.3-command-buffer",
+        "android.hardware.graphics.composer@2.4-command-buffer",
     ],
     export_static_lib_headers: [
         "libcompositionengine",
         "librenderengine",
         "libserviceutils",
-        "libtimestats",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.allocator@2.0",
@@ -96,6 +96,7 @@
         "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.3",
         "libhidlbase",
+        "libtimestats",
     ],
     // TODO (marissaw): this library is not used by surfaceflinger. This is here so
     // the library compiled in a way that is accessible to system partition when running
@@ -231,7 +232,6 @@
         "liblog",
         "libprocessgroup",
         "libsync",
-        "libtimestats_proto",
         "libutils",
     ],
     static_libs: [
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3b1b796..7845cab 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "BufferLayer"
@@ -795,3 +799,6 @@
 #if defined(__gl2_h_)
 #error "don't include gl2/gl2.h in this file"
 #endif
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index ea55795..5e04d95 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "BufferLayerConsumer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -519,3 +523,6 @@
     }
 }
 }; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e4e4bc7..b55e62b 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "BufferQueueLayer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -117,6 +121,18 @@
     return isDue || !isPlausible;
 }
 
+bool BufferQueueLayer::setFrameRate(float frameRate) {
+    float oldFrameRate = 0.f;
+    status_t result = mConsumer->getFrameRate(&oldFrameRate);
+    bool frameRateChanged = result < 0 || frameRate != oldFrameRate;
+    mConsumer->setFrameRate(frameRate);
+    return frameRateChanged;
+}
+
+float BufferQueueLayer::getFrameRate() const {
+    return mLatchedFrameRate;
+}
+
 // -----------------------------------------------------------------------
 // Interface implementation for BufferLayer
 // -----------------------------------------------------------------------
@@ -547,6 +563,9 @@
     mBufferInfo.mApi = mConsumer->getCurrentApi();
     mBufferInfo.mPixelFormat = mFormat;
     mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
+    float latchedFrameRate;
+    mConsumer->getFrameRate(&latchedFrameRate);
+    mLatchedFrameRate = latchedFrameRate;
 }
 
 sp<Layer> BufferQueueLayer::createClone() {
@@ -612,3 +631,6 @@
 // -----------------------------------------------------------------------
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index b040556..0777953 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -55,6 +55,10 @@
     int32_t getQueuedFrameCount() const override;
 
     bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
+
+    bool setFrameRate(float frameRate) override;
+    float getFrameRate() const override;
+
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
@@ -151,6 +155,8 @@
     std::atomic<bool> mSidebandStreamChanged{false};
 
     sp<ContentsChangedListener> mContentsChangedListener;
+
+    std::atomic<float> mLatchedFrameRate = 0.f;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 19fa70b..287fe89 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "BufferStateLayer"
@@ -683,3 +687,6 @@
     return layer;
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index f331364..fb72ab8 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -131,3 +135,6 @@
 
 // ---------------------------------------------------------------------------
 }; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 8bfa569..6aea88a 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "ColorLayer"
@@ -116,3 +120,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 78f8104..42d9875 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -22,20 +22,20 @@
         "libnativewindow",
         "libprotobuf-cpp-lite",
         "libsync",
-        "libtimestats_proto",
+        "libtimestats",
         "libui",
         "libutils",
     ],
     static_libs: [
         "libmath",
         "librenderengine",
-        "libtimestats",
         "libtrace_proto",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
         "android.hardware.graphics.composer@2.3-command-buffer",
+        "android.hardware.graphics.composer@2.4-command-buffer",
         "libsurfaceflinger_headers",
     ],
 }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index a64fdbf..3dbd25e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -63,6 +63,9 @@
     // The alpha value for this layer
     float alpha{1.f};
 
+    // Background blur in pixels
+    int backgroundBlurRadius{0};
+
     // The transform from layer local coordinates to composition coordinates
     ui::Transform geomLayerTransform;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 076fdad..a280c75 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -162,7 +162,7 @@
     virtual void setCompositionEnabled(bool) = 0;
 
     // Sets the projection state to use
-    virtual void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+    virtual void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
                                const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
     // Sets the bounds to use
     virtual void setBounds(const ui::Size&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 159e928..e2d01ed 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -36,7 +36,7 @@
     bool isValid() const override;
     std::optional<DisplayId> getDisplayId() const override;
     void setCompositionEnabled(bool) override;
-    void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+    void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
                        const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
     void setBounds(const ui::Size&) override;
     void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
@@ -116,6 +116,7 @@
 
 private:
     void dirtyEntireOutput();
+    compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
     ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
     compositionengine::Output::ColorProfile pickColorProfile(
             const compositionengine::CompositionRefreshArgs&) const;
@@ -126,6 +127,7 @@
     std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
 
     ReleasedLayers mReleasedLayers;
+    OutputLayer* mLayerRequestingBackgroundBlur = nullptr;
 };
 
 // This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 7f5bd06..367e8ca 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -38,7 +38,7 @@
 
     MOCK_METHOD1(setCompositionEnabled, void(bool));
     MOCK_METHOD6(setProjection,
-                 void(const ui::Transform&, int32_t, const Rect&, const Rect&, const Rect&, bool));
+                 void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&, bool));
     MOCK_METHOD1(setBounds, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
 
diff --git a/services/surfaceflinger/CompositionEngine/mock/Display.cpp b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
index 01cf112..dc303d7 100644
--- a/services/surfaceflinger/CompositionEngine/mock/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/mock/Display.h>
 
 namespace android::compositionengine::mock {
@@ -24,3 +28,6 @@
 Display::~Display() = default;
 
 } // namespace android::compositionengine::mock
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/mock/Layer.cpp b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
index 08483cb..a733bac 100644
--- a/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/mock/Layer.h>
 
 namespace android::compositionengine::mock {
@@ -24,3 +28,6 @@
 Layer::~Layer() = default;
 
 } // namespace android::compositionengine::mock
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp b/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
index 607eaad..232756f 100644
--- a/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/mock/LayerFE.h>
 
 namespace android::compositionengine::mock {
@@ -24,3 +28,6 @@
 LayerFE::~LayerFE() = default;
 
 } // namespace android::compositionengine::mock
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/mock/Output.cpp b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
index 44df4c3..2608ef0 100644
--- a/services/surfaceflinger/CompositionEngine/mock/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/mock/Output.h>
 
 namespace android::compositionengine::mock {
@@ -24,3 +28,6 @@
 Output::~Output() = default;
 
 } // namespace android::compositionengine::mock
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
index 4da9377..c1153e3 100644
--- a/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/mock/OutputLayer.h>
 
 namespace android::compositionengine::mock {
@@ -24,3 +28,6 @@
 OutputLayer::~OutputLayer() = default;
 
 } // namespace android::compositionengine::mock
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 5eabecd..030c703 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/CompositionRefreshArgs.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/OutputLayer.h>
@@ -155,3 +159,6 @@
 
 } // namespace impl
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index e885629..20f765c 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/CompositionRefreshArgs.h>
@@ -337,3 +341,6 @@
 }
 
 } // namespace android::compositionengine::impl
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index f72862b..1e7c97c 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/impl/HwcBufferCache.h>
 #include <gui/BufferQueue.h>
 #include <ui/GraphicBuffer.h>
@@ -31,7 +35,7 @@
         slot >= BufferQueue::NUM_BUFFER_SLOTS) {
         *outSlot = 0;
     } else {
-        *outSlot = slot;
+        *outSlot = static_cast<uint32_t>(slot);
     }
 
     auto& currentBuffer = mBuffers[*outSlot];
@@ -48,3 +52,6 @@
 }
 
 } // namespace android::compositionengine::impl
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
index ecacaee..22ecd33 100644
--- a/services/surfaceflinger/CompositionEngine/src/Layer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <android-base/stringprintf.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/LayerFECompositionState.h>
@@ -41,3 +45,6 @@
 
 } // namespace impl
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index e740529..8065e65 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <android-base/stringprintf.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/impl/DumpHelpers.h>
@@ -57,6 +61,7 @@
     out.append("\n      ");
     dumpVal(out, "blend", toString(blendMode), blendMode);
     dumpVal(out, "alpha", alpha);
+    dumpVal(out, "backgroundBlurRadius", backgroundBlurRadius);
 
     out.append("\n      ");
     dumpVal(out, "type", type);
@@ -86,3 +91,6 @@
 }
 
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 28d2653..bffb74f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <thread>
 
 #include <android-base/stringprintf.h>
@@ -97,7 +101,7 @@
     dirtyEntireOutput();
 }
 
-void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
+void Output::setProjection(const ui::Transform& transform, uint32_t orientation, const Rect& frame,
                            const Rect& viewport, const Rect& scissor, bool needsFiltering) {
     auto& outputState = editState();
     outputState.transform = transform;
@@ -429,7 +433,7 @@
     if (layerFEState.shadowRadius > 0.0f) {
         // if the layer casts a shadow, offset the layers visible region and
         // calculate the shadow region.
-        const int32_t inset = layerFEState.shadowRadius * -1.0f;
+        const auto inset = static_cast<int32_t>(ceilf(layerFEState.shadowRadius) * -1.0f);
         Rect visibleRectWithShadows(visibleRect);
         visibleRectWithShadows.inset(inset, inset, inset, inset);
         visibleRegion.set(visibleRectWithShadows);
@@ -453,7 +457,7 @@
     }
 
     // compute the opaque region
-    const int32_t layerOrientation = tr.getOrientation();
+    const auto layerOrientation = tr.getOrientation();
     if (layerFEState.isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) {
         // If we one of the simple category of transforms (0/90/180/270 rotation
         // + any flip), then the opaque region is the layer's footprint.
@@ -574,15 +578,33 @@
         return;
     }
 
+    mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition();
+    bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr;
+
     for (auto* layer : getOutputLayersOrderedByZ()) {
         layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
-                                      refreshArgs.devOptForceClientComposition);
+                                      refreshArgs.devOptForceClientComposition ||
+                                              forceClientComposition);
+
+        if (mLayerRequestingBackgroundBlur == layer) {
+            forceClientComposition = false;
+        }
 
         // Send the updated state to the HWC, if appropriate.
         layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
     }
 }
 
+compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
+    compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
+    for (auto* layer : getOutputLayersOrderedByZ()) {
+        if (layer->getLayer().getFEState().backgroundBlurRadius > 0) {
+            layerRequestingBgComposition = layer;
+        }
+    }
+    return layerRequestingBgComposition;
+}
+
 void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) {
     setColorProfile(pickColorProfile(refreshArgs));
 }
@@ -788,6 +810,7 @@
                                                       outputState.usesClientComposition};
     base::unique_fd readyFence;
     if (!hasClientComposition) {
+        setExpensiveRenderingExpected(false);
         return readyFence;
     }
 
@@ -849,11 +872,12 @@
     }
 
     // We boost GPU frequency here because there will be color spaces conversion
-    // and it's expensive. We boost the GPU frequency so that GPU composition can
-    // finish in time. We must reset GPU frequency afterwards, because high frequency
-    // consumes extra battery.
+    // or complex GPU shaders and it's expensive. We boost the GPU frequency so that
+    // GPU composition can finish in time. We must reset GPU frequency afterwards,
+    // because high frequency consumes extra battery.
     const bool expensiveRenderingExpected =
-            clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+            clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3 ||
+            mLayerRequestingBackgroundBlur != nullptr;
     if (expensiveRenderingExpected) {
         setExpensiveRenderingExpected(true);
     }
@@ -871,10 +895,6 @@
                                                      new Fence(dup(readyFence.get()))));
     }
 
-    if (expensiveRenderingExpected) {
-        setExpensiveRenderingExpected(false);
-    }
-
     return readyFence;
 }
 
@@ -1061,3 +1081,6 @@
 
 } // namespace impl
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 82d2422..914a047 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <android-base/stringprintf.h>
 #include <compositionengine/DisplayColorProfile.h>
 #include <compositionengine/Layer.h>
@@ -388,7 +392,8 @@
               outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
+    if (auto error = hwcLayer->setInfo(static_cast<uint32_t>(outputIndependentState.type),
+                                       static_cast<uint32_t>(outputIndependentState.appId));
         error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
               to_string(error).c_str(), static_cast<int32_t>(error));
@@ -645,3 +650,6 @@
 
 } // namespace impl
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index cc3c54c..20c8f9a 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/impl/DumpHelpers.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 
@@ -70,3 +74,6 @@
 }
 
 } // namespace android::compositionengine::impl
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 949feb4..e981172 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <android-base/stringprintf.h>
@@ -87,7 +91,8 @@
 }
 
 void RenderSurface::setDisplaySize(const ui::Size& size) {
-    mDisplaySurface->resizeBuffers(size.width, size.height);
+    mDisplaySurface->resizeBuffers(static_cast<uint32_t>(size.width),
+                                   static_cast<uint32_t>(size.height));
     mSize = size;
 }
 
@@ -249,3 +254,6 @@
 
 } // namespace impl
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 989494d..bcaa529 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/CompositionRefreshArgs.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/impl/CompositionEngine.h>
@@ -135,14 +139,14 @@
 struct CompositionEngineUpdateCursorAsyncTest : public CompositionEngineTest {
 public:
     CompositionEngineUpdateCursorAsyncTest() {
-        EXPECT_CALL(*mOutput1, getOutputLayerCount()).WillRepeatedly(Return(0));
+        EXPECT_CALL(*mOutput1, getOutputLayerCount()).WillRepeatedly(Return(0u));
         EXPECT_CALL(*mOutput1, getOutputLayerOrderedByZByIndex(_)).Times(0);
 
-        EXPECT_CALL(*mOutput2, getOutputLayerCount()).WillRepeatedly(Return(1));
+        EXPECT_CALL(*mOutput2, getOutputLayerCount()).WillRepeatedly(Return(1u));
         EXPECT_CALL(*mOutput2, getOutputLayerOrderedByZByIndex(0))
                 .WillRepeatedly(Return(&mOutput2OutputLayer1));
 
-        EXPECT_CALL(*mOutput3, getOutputLayerCount()).WillRepeatedly(Return(2));
+        EXPECT_CALL(*mOutput3, getOutputLayerCount()).WillRepeatedly(Return(2u));
         EXPECT_CALL(*mOutput3, getOutputLayerOrderedByZByIndex(0))
                 .WillRepeatedly(Return(&mOutput3OutputLayer1));
         EXPECT_CALL(*mOutput3, getOutputLayerOrderedByZByIndex(1))
@@ -298,3 +302,6 @@
 
 } // namespace
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 3a4df74..0fe5843 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <cmath>
 
 #include <compositionengine/DisplayColorProfileCreationArgs.h>
@@ -700,6 +704,9 @@
     // We expect no calls to queueBuffer if composition was skipped.
     EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
 
+    // Expect a call to signal no expensive rendering since there is no client composition.
+    EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false));
+
     mDisplay->editState().isEnabled = true;
     mDisplay->editState().usesClientComposition = false;
     mDisplay->editState().viewport = Rect(0, 0, 1, 1);
@@ -830,3 +837,6 @@
 
 } // namespace
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
index 787f973..44df289 100644
--- a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gtest/gtest.h>
 
 #include <compositionengine/LayerCreationArgs.h>
@@ -59,3 +63,6 @@
 
 } // namespace
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0e579fa..bd830be 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <compositionengine/mock/CompositionEngine.h>
@@ -1054,3 +1058,6 @@
 
 } // namespace
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cb6c50c..730cac8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <cmath>
 
 #include <android-base/stringprintf.h>
@@ -60,8 +64,8 @@
 constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
 
 const mat4 kIdentity;
-const mat4 kNonIdentityHalf = mat4() * 0.5;
-const mat4 kNonIdentityQuarter = mat4() * 0.25;
+const mat4 kNonIdentityHalf = mat4() * 0.5f;
+const mat4 kNonIdentityQuarter = mat4() * 0.25f;
 
 constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting =
         static_cast<OutputColorSetting>(0x100);
@@ -134,6 +138,10 @@
         EXPECT_CALL(mLayer1, editFEState()).WillRepeatedly(ReturnRef(mLayer1FEState));
         EXPECT_CALL(mLayer2, editFEState()).WillRepeatedly(ReturnRef(mLayer2FEState));
         EXPECT_CALL(mLayer3, editFEState()).WillRepeatedly(ReturnRef(mLayer3FEState));
+
+        EXPECT_CALL(mLayer1, getFEState()).WillRepeatedly(ReturnRef(mLayer1FEState));
+        EXPECT_CALL(mLayer2, getFEState()).WillRepeatedly(ReturnRef(mLayer2FEState));
+        EXPECT_CALL(mLayer3, getFEState()).WillRepeatedly(ReturnRef(mLayer3FEState));
     }
 
     void injectLayer(std::unique_ptr<mock::OutputLayer> layer) {
@@ -980,7 +988,7 @@
     };
 
     OutputCollectVisibleLayersTest() {
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u));
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0))
                 .WillRepeatedly(Return(&mLayer1.outputLayer));
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1))
@@ -1004,7 +1012,7 @@
 
 TEST_F(OutputCollectVisibleLayersTest, doesMinimalWorkIfNoLayers) {
     mRefreshArgs.layers.clear();
-    EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0));
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
 
     EXPECT_CALL(mOutput, setReleasedLayers(Ref(mRefreshArgs)));
     EXPECT_CALL(mOutput, finalizePendingOutputLayers());
@@ -1054,7 +1062,7 @@
         EXPECT_CALL(*mLayer, editFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
 
         EXPECT_CALL(mOutput, belongsInOutput(mLayer.get())).WillRepeatedly(Return(true));
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
                 .WillRepeatedly(Return(&mOutputLayer));
 
@@ -1619,7 +1627,7 @@
     // When the outputColorSetting is set to kUnmanaged, the implementation sets
     // a simple default color profile without looking at anything else.
 
-    EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3));
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u));
     EXPECT_CALL(mOutput,
                 setColorProfile(ColorProfileEq(
                         ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
@@ -1634,7 +1642,7 @@
 struct OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile
       : public OutputUpdateColorProfileTest {
     OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile() {
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
         mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
         mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
     }
@@ -1682,7 +1690,7 @@
 struct OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile
       : public OutputUpdateColorProfileTest {
     OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile() {
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
         EXPECT_CALL(*mDisplayColorProfile,
                     getBestColorMode(ui::Dataspace::V0_SRGB, ui::RenderIntent::ENHANCE, _, _, _))
                 .WillRepeatedly(DoAll(SetArgPointee<2>(ui::Dataspace::UNKNOWN),
@@ -1738,7 +1746,7 @@
         mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
         mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
 
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u));
         EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
     }
 
@@ -1860,7 +1868,7 @@
 
         mLayer1.mLayerFEState.dataspace = ui::Dataspace::DISPLAY_BT2020;
 
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
         EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
     }
 
@@ -1913,7 +1921,7 @@
     OutputUpdateColorProfileTest_Hdr() {
         mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
         mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
         EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
     }
 
@@ -2193,7 +2201,7 @@
         mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced;
         mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
         mLayer1.mLayerFEState.dataspace = ui::Dataspace::BT2020_PQ;
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1));
+        EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
         EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return());
         EXPECT_CALL(*mDisplayColorProfile, hasLegacyHdrSupport(ui::Dataspace::BT2020_PQ))
                 .WillRepeatedly(Return(false));
@@ -2834,7 +2842,7 @@
 const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004};
 const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008};
 const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012};
-const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5};
+const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f};
 const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}};
 const HdrCapabilities OutputComposeSurfacesTest::
         kHdrCapabilities{{},
@@ -2842,9 +2850,11 @@
                          OutputComposeSurfacesTest::kDefaultAvgLuminance,
                          OutputComposeSurfacesTest::kDefaultMinLuminance};
 
-TEST_F(OutputComposeSurfacesTest, doesNothingIfNoClientComposition) {
+TEST_F(OutputComposeSurfacesTest, doesNothingButSignalNoExpensiveRenderingIfNoClientComposition) {
     mOutput.mState.usesClientComposition = false;
 
+    EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
+
     verify().execute().expectAFenceWasReturned();
 }
 
@@ -3163,7 +3173,6 @@
 
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
 
     mOutput.composeSurfaces(kDebugRegion);
 }
@@ -3407,7 +3416,7 @@
     EXPECT_EQ(mLayers[1].mRELayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
     EXPECT_FALSE(requests[0].source.buffer.buffer);
     EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor);
-    EXPECT_EQ(half{0.f}, requests[0].alpha);
+    EXPECT_EQ(0.f, static_cast<float>(requests[0].alpha));
     EXPECT_EQ(true, requests[0].disableBlending);
 
     EXPECT_EQ(mLayers[2].mRELayerSettings, requests[1]);
@@ -3632,6 +3641,29 @@
                                                                 kDisplayDataspace));
 }
 
+TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) {
+    // Layer requesting blur, or below, should request client composition.
+    EXPECT_CALL(*mOutputLayer1, updateCompositionState(false, true));
+    EXPECT_CALL(*mOutputLayer1, writeStateToHWC(false));
+    EXPECT_CALL(*mOutputLayer2, updateCompositionState(false, true));
+    EXPECT_CALL(*mOutputLayer2, writeStateToHWC(false));
+    EXPECT_CALL(*mOutputLayer3, updateCompositionState(false, false));
+    EXPECT_CALL(*mOutputLayer3, writeStateToHWC(false));
+
+    mLayer2FEState.backgroundBlurRadius = 10;
+
+    injectLayer(std::move(mOutputLayer1));
+    injectLayer(std::move(mOutputLayer2));
+    injectLayer(std::move(mOutputLayer3));
+
+    mOutput->editState().isEnabled = true;
+
+    CompositionRefreshArgs args;
+    args.updatingGeometryThisFrame = false;
+    args.devOptForceClientComposition = false;
+    mOutput->updateAndWriteCompositionState(args);
+}
+
 TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenRequests) {
     // In split-screen landscape mode, the screen is rotated 90 degrees, with
     // one layer on the left covering the left side of the output, and one layer
@@ -3780,3 +3812,6 @@
 
 } // namespace
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index fd47e45..4fba10b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <cstdarg>
 #include <cstdint>
 
@@ -350,3 +354,6 @@
 
 } // namespace
 } // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index ab664be..841e79f 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "ContainerLayer"
@@ -39,3 +43,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e0dc3e7..e2122d1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "DisplayDevice"
@@ -327,3 +331,6 @@
 std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
 
 }  // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index eb032f3..9d8f31b 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "HwcComposer"
 
@@ -1333,8 +1337,7 @@
     uint16_t length = 0;
 
     while (!isEmpty()) {
-        auto command_2_1 = reinterpret_cast<V2_1::IComposerClient::Command*>(&command);
-        if (!beginCommand(command_2_1, &length)) {
+        if (!beginCommand(&command, &length)) {
             break;
         }
 
@@ -1361,6 +1364,9 @@
         case IComposerClient::Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
             parsed = parseSetPresentOrValidateDisplayResult(length);
             break;
+        case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY:
+            parsed = parseSetClientTargetProperty(length);
+            break;
         default:
             parsed = false;
             break;
@@ -1498,6 +1504,15 @@
     return true;
 }
 
+bool CommandReader::parseSetClientTargetProperty(uint16_t length) {
+    if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
+        return false;
+    }
+    mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
+    mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
+    return true;
+}
+
 void CommandReader::resetData()
 {
     mErrors.clear();
@@ -1622,3 +1637,6 @@
 } // namespace Hwc2
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 301f54f..6f0f38a 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -29,7 +29,7 @@
 #include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/composer/2.4/IComposer.h>
 #include <android/hardware/graphics/composer/2.4/IComposerClient.h>
-#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
 #include <ui/DisplayedFrameStats.h>
@@ -63,8 +63,8 @@
 using V2_1::Display;
 using V2_1::Error;
 using V2_1::Layer;
-using V2_3::CommandReaderBase;
-using V2_3::CommandWriterBase;
+using V2_4::CommandReaderBase;
+using V2_4::CommandWriterBase;
 using V2_4::IComposer;
 using V2_4::IComposerCallback;
 using V2_4::IComposerClient;
@@ -280,6 +280,7 @@
     bool parseSetPresentFence(uint16_t length);
     bool parseSetReleaseFences(uint16_t length);
     bool parseSetPresentOrValidateDisplayResult(uint16_t length);
+    bool parseSetClientTargetProperty(uint16_t length);
 
     struct ReturnData {
         uint32_t displayRequests = 0;
@@ -296,6 +297,13 @@
         std::vector<int> releaseFences;
 
         uint32_t presentOrValidateState;
+
+        // Composer 2.4 implementation can return a client target property
+        // structure to indicate the client target properties that hardware
+        // composer requests. The composer client must change the client target
+        // properties to match this request.
+        IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+                                                                   Dataspace::UNKNOWN};
     };
 
     std::vector<CommandError> mErrors;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index ba7818d..277081f 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "DisplayIdentification"
 
@@ -204,3 +208,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7370b0c..36544b6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -15,6 +15,10 @@
  ** limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FramebufferSurface"
@@ -193,3 +197,6 @@
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 12b0ddd..41e7879 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 
 #undef LOG_TAG
@@ -977,3 +981,6 @@
 
 } // namespace impl
 } // namespace HWC2
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1960f43..153cfe7 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 
 #undef LOG_TAG
@@ -948,3 +952,6 @@
 
 } // namespace impl
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 56b0ea6..fba3261 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #include "VirtualDisplaySurface.h"
 
@@ -694,3 +698,6 @@
 // ---------------------------------------------------------------------------
 } // namespace android
 // ---------------------------------------------------------------------------
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Effects/Daltonizer.cpp b/services/surfaceflinger/Effects/Daltonizer.cpp
index 01c9c0f..a7090c5 100644
--- a/services/surfaceflinger/Effects/Daltonizer.cpp
+++ b/services/surfaceflinger/Effects/Daltonizer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "Daltonizer.h"
 #include <math/mat4.h>
 
@@ -171,3 +175,6 @@
 }
 
 } /* namespace android */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
index a532fc1..3b60952 100644
--- a/services/surfaceflinger/EventLog/EventLog.cpp
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <log/log.h>
@@ -124,3 +128,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
index 4418116..b986f38 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.cpp
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "FrameTracer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -179,3 +183,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index a6e511e..8ad805b 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // This is needed for stdint.h to define INT64_MAX in C++
 #define __STDC_LIMIT_MACROS
 
@@ -246,3 +250,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 37714f5..f4d4329 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "Layer"
@@ -105,11 +109,14 @@
     mCurrentState.hdrMetadata.validTypes = 0;
     mCurrentState.surfaceDamageRegion = Region::INVALID_REGION;
     mCurrentState.cornerRadius = 0.0f;
+    mCurrentState.backgroundBlurRadius = 0;
     mCurrentState.api = -1;
     mCurrentState.hasColorTransform = false;
     mCurrentState.colorSpaceAgnostic = false;
+    mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
     mCurrentState.metadata = args.metadata;
     mCurrentState.shadowRadius = 0.f;
+    mCurrentState.frameRate = 0.f;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
@@ -442,6 +449,7 @@
 
     compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
     compositionState.alpha = alpha;
+    compositionState.backgroundBlurRadius = drawingState.backgroundBlurRadius;
 }
 
 void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const {
@@ -569,6 +577,7 @@
 
     layerSettings.alpha = alpha;
     layerSettings.sourceDataspace = getDataSpace();
+    layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
     return layerSettings;
 }
 
@@ -1097,6 +1106,16 @@
     return true;
 }
 
+bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
+    if (mCurrentState.backgroundBlurRadius == backgroundBlurRadius) return false;
+
+    mCurrentState.sequence++;
+    mCurrentState.backgroundBlurRadius = backgroundBlurRadius;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
         bool allowNonRectPreservingTransforms) {
     ui::Transform t;
@@ -1120,6 +1139,7 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+
 bool Layer::setFlags(uint8_t flags, uint8_t mask) {
     const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
     if (mCurrentState.flags == newFlags) return false;
@@ -1176,6 +1196,29 @@
     return true;
 }
 
+bool Layer::setFrameRateSelectionPriority(int32_t priority) {
+    if (mCurrentState.frameRateSelectionPriority == priority) return false;
+    mCurrentState.frameRateSelectionPriority = priority;
+    mCurrentState.sequence++;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+int32_t Layer::getFrameRateSelectionPriority() const {
+    // Check if layer has priority set.
+    if (mDrawingState.frameRateSelectionPriority != PRIORITY_UNSET) {
+        return mDrawingState.frameRateSelectionPriority;
+    }
+    // If not, search whether its parents have it set.
+    sp<Layer> parent = getParent();
+    if (parent != nullptr) {
+        return parent->getFrameRateSelectionPriority();
+    }
+
+    return Layer::PRIORITY_UNSET;
+}
+
 uint32_t Layer::getLayerStack() const {
     auto p = mDrawingParent.promote();
     if (p == nullptr) {
@@ -1196,6 +1239,22 @@
     return true;
 }
 
+bool Layer::setFrameRate(float frameRate) {
+    if (mCurrentState.frameRate == frameRate) {
+        return false;
+    }
+
+    mCurrentState.sequence++;
+    mCurrentState.frameRate = frameRate;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+float Layer::getFrameRate() const {
+    return getDrawingState().frameRate;
+}
+
 void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
     ATRACE_CALL();
     mCurrentState.barrierLayer_legacy = barrierLayer;
@@ -1827,6 +1886,10 @@
     return half4(color.r, color.g, color.b, getAlpha());
 }
 
+int32_t Layer::getBackgroundBlurRadius() const {
+    return getDrawingState().backgroundBlurRadius;
+}
+
 Layer::RoundedCornerState Layer::getRoundedCornerState() const {
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
@@ -1893,7 +1956,7 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
-void Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) const {
+LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) const {
     LayerProto* layerProto = layersProto.add_layers();
     writeToProtoDrawingState(layerProto, traceFlags);
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
@@ -1901,6 +1964,8 @@
     for (const sp<Layer>& layer : mDrawingChildren) {
         layer->writeToProto(layersProto, traceFlags);
     }
+
+    return layerProto;
 }
 
 void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const {
@@ -2302,3 +2367,6 @@
 #if defined(__gl2_h_)
 #error "don't include gl2/gl2.h in this file"
 #endif
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 76edfa5..ffe004f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -96,6 +96,7 @@
 
 class Layer : public compositionengine::LayerFE {
     static std::atomic<int32_t> sSequence;
+    static constexpr int32_t PRIORITY_UNSET = -1;
 
 public:
     mutable bool contentDirty{false};
@@ -178,6 +179,7 @@
 
         half4 color;
         float cornerRadius;
+        int backgroundBlurRadius;
 
         bool inputInfoChanged;
         InputWindowInfo inputInfo;
@@ -220,6 +222,11 @@
         // Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will
         // be rendered around the layer.
         float shadowRadius;
+
+        // Priority of the layer assigned by Window Manager.
+        int32_t frameRateSelectionPriority;
+
+        float frameRate;
     };
 
     explicit Layer(const LayerCreationArgs& args);
@@ -293,6 +300,9 @@
     // The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
     // from which we inferred the rounded corner radius.
     virtual bool setCornerRadius(float cornerRadius);
+    // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
+    // is specified in pixels.
+    virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
     virtual bool setTransparentRegionHint(const Region& transparent);
     virtual bool setFlags(uint8_t flags, uint8_t mask);
     virtual bool setLayerStack(uint32_t layerStack);
@@ -337,6 +347,10 @@
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
     virtual bool setColorSpaceAgnostic(const bool agnostic);
     bool setShadowRadius(float shadowRadius);
+    virtual bool setFrameRateSelectionPriority(int32_t priority);
+    //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
+    //  rate priority from its parent.
+    virtual int32_t getFrameRateSelectionPriority() const;
 
     virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
 
@@ -454,8 +468,8 @@
 
     bool isRemovedFromCurrentState() const;
 
-    void writeToProto(LayersProto& layersProto,
-                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    LayerProto* writeToProto(LayersProto& layersProto,
+                             uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
 
     // Write states that are modified by the main thread. This includes drawing
     // state as well as buffer data. This should be called in the main or tracing
@@ -653,6 +667,7 @@
     // down the hierarchy).
     half getAlpha() const;
     half4 getColor() const;
+    int32_t getBackgroundBlurRadius() const;
 
     // Returns how rounded corners should be drawn for this layer.
     // This will traverse the hierarchy until it reaches its root, finding topmost rounded
@@ -729,6 +744,9 @@
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
 
+    virtual bool setFrameRate(float frameRate);
+    virtual float getFrameRate() const;
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -755,6 +773,7 @@
 
     // For unit tests
     friend class TestableSurfaceFlinger;
+    friend class RefreshRateSelectionTest;
 
     virtual void commitTransaction(const State& stateToCommit);
 
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index b402270..0fe1421 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerProtoHelper.h"
 
 namespace android {
@@ -165,3 +169,6 @@
 
 } // namespace surfaceflinger
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 412f977..d3364a0 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerRejecter.h"
 
 #include <gui/BufferItem.h>
@@ -136,3 +140,6 @@
 }
 
 }  // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 8271fd9..7c959b9 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerVector.h"
 #include "Layer.h"
 
@@ -83,3 +87,6 @@
      }
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 7a959f7..40a63d7 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "MonitoredProducer.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
@@ -158,6 +162,10 @@
     return mProducer->setAutoPrerotation(autoPrerotation);
 }
 
+status_t MonitoredProducer::setFrameRate(float frameRate) {
+    return mProducer->setFrameRate(frameRate);
+}
+
 IBinder* MonitoredProducer::onAsBinder() {
     return this;
 }
@@ -168,3 +176,6 @@
 
 // ---------------------------------------------------------------------------
 }; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 788919b..4bda831 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -71,6 +71,7 @@
     virtual status_t getUniqueId(uint64_t* outId) const override;
     virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
     virtual status_t setAutoPrerotation(bool autoPrerotation) override;
+    virtual status_t setFrameRate(float frameRate) override;
 
     // The Layer which created this producer, and on which queued Buffer's will be displayed.
     sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 4ef64b6..f2bc65d 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,5 +5,6 @@
 lpy@google.com
 marissaw@google.com
 racarr@google.com
+steventhomas@google.com
 stoza@google.com
 vhau@google.com
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index c69859e..33e5796 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "RefreshRateOverlay.h"
 #include "Client.h"
 #include "Layer.h"
@@ -211,3 +215,6 @@
 }
 
 }; // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 73de4f8..0031d70 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
@@ -472,3 +476,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
index 93759e8..9a6c853 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2017 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "RenderArea.h"
 
 namespace android {
@@ -13,3 +33,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 4bdfad9..ca41608 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
@@ -847,3 +851,6 @@
 } // namespace impl
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index bd4b0ec..776e984 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "DispSyncSource.h"
@@ -104,3 +108,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/EventControlThread.cpp b/services/surfaceflinger/Scheduler/EventControlThread.cpp
index 85a7f82..7f9db9c 100644
--- a/services/surfaceflinger/Scheduler/EventControlThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventControlThread.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <pthread.h>
 #include <sched.h>
 #include <sys/resource.h>
@@ -73,3 +77,6 @@
 
 } // namespace impl
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5bdef58..14e3ec6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <pthread.h>
@@ -517,3 +521,6 @@
 
 } // namespace impl
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index cf79d9f..abf0cd6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LayerHistory"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -39,6 +43,9 @@
 namespace {
 
 bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
+    if (layer.getFrameRate() > .0f) {
+        return layer.isVisible();
+    }
     return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
 }
 
@@ -48,6 +55,12 @@
     return atoi(value);
 }
 
+bool useFrameRatePriority() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.use_frame_rate_priority", value, "1");
+    return atoi(value);
+}
+
 void trace(const wp<Layer>& weak, int fps) {
     const auto layer = weak.promote();
     if (!layer) return;
@@ -60,7 +73,8 @@
 
 } // namespace
 
-LayerHistory::LayerHistory() : mTraceEnabled(traceEnabled()) {}
+LayerHistory::LayerHistory()
+      : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {}
 LayerHistory::~LayerHistory() = default;
 
 void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highRefreshRate) {
@@ -94,16 +108,44 @@
     partitionLayers(now);
 
     // Find the maximum refresh rate among recently active layers.
-    for (const auto& [layer, info] : activeLayers()) {
+    for (const auto& [activeLayer, info] : activeLayers()) {
         const bool recent = info->isRecentlyActive(now);
+
         if (recent || CC_UNLIKELY(mTraceEnabled)) {
             const float refreshRate = info->getRefreshRate(now);
             if (recent && refreshRate > maxRefreshRate) {
+                if (const auto layer = activeLayer.promote(); layer) {
+                    const int32_t priority = layer->getFrameRateSelectionPriority();
+                    // TODO(b/142507166): This is where the scoring algorithm should live.
+                    // Layers should be organized by priority
+                    ALOGD("Layer has priority: %d", priority);
+                }
+            }
+        }
+    }
+
+    for (const auto& [weakLayer, info] : activeLayers()) {
+        const bool recent = info->isRecentlyActive(now);
+        auto layer = weakLayer.promote();
+        // Only use the layer if the reference still exists.
+        if (layer || CC_UNLIKELY(mTraceEnabled)) {
+            float refreshRate = 0.f;
+            // Default content refresh rate is only used when dealing with recent layers.
+            if (recent) {
+                refreshRate = info->getRefreshRate(now);
+            }
+            // Check if frame rate was set on layer.
+            float frameRate = layer->getFrameRate();
+            if (frameRate > 0.f) {
+                // Override content detection refresh rate, if it was set.
+                refreshRate = frameRate;
+            }
+            if (refreshRate > maxRefreshRate) {
                 maxRefreshRate = refreshRate;
             }
 
             if (CC_UNLIKELY(mTraceEnabled)) {
-                trace(layer, std::round(refreshRate));
+                trace(weakLayer, std::round(refreshRate));
             }
         }
     }
@@ -157,4 +199,23 @@
     mActiveLayersEnd = 0;
 }
 
+bool LayerHistory::hasClientSpecifiedFrameRate() {
+    std::lock_guard lock(mLock);
+    for (const auto& [weakLayer, info] : activeLayers()) {
+        auto layer = weakLayer.promote();
+        if (layer) {
+            float frameRate = layer->getFrameRate();
+            // Found a layer that has a frame rate set on it.
+            if (fabs(frameRate) > 0.f) {
+                return true;
+            }
+        }
+    }
+    // Did not find any layers that have frame rate.
+    return false;
+}
+
 } // namespace android::scheduler::impl
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index d92e5c3..f217134 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -53,6 +53,9 @@
     virtual Summary summarize(nsecs_t now) = 0;
 
     virtual void clear() = 0;
+
+    // Checks whether any of the active layers have a desired frame rate bit set on them.
+    virtual bool hasClientSpecifiedFrameRate() = 0;
 };
 
 namespace impl {
@@ -75,6 +78,10 @@
 
     void clear() override;
 
+    // Traverses all active layers and checks whether any of them have a desired frame
+    // rate bit set on them.
+    bool hasClientSpecifiedFrameRate() override;
+
 private:
     friend class android::scheduler::LayerHistoryTest;
     friend TestableScheduler;
@@ -106,6 +113,9 @@
 
     // Whether to emit systrace output and debug logs.
     const bool mTraceEnabled;
+
+    // Whether to use priority sent from WindowManager to determine the relevancy of the layer.
+    const bool mUseFrameRatePriority;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 5318b00..005d157 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <errno.h>
 #include <stdint.h>
 #include <sys/types.h>
@@ -159,3 +163,6 @@
 
 } // namespace impl
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 13014c7..106aa9b 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "PhaseOffsets.h"
 
 #include <cutils/properties.h>
@@ -330,3 +334,6 @@
 
 } // namespace impl
 } // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 692ded9..45d1f23 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #include "RefreshRateConfigs.h"
 
@@ -217,3 +221,5 @@
 }
 
 } // namespace android::scheduler
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 73dc753..0b645c4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "Scheduler"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -418,18 +422,20 @@
 }
 
 void Scheduler::notifyTouchEvent() {
-    if (mTouchTimer) {
-        mTouchTimer->reset();
-    }
-
-    if (mSupportKernelTimer && mIdleTimer) {
-        mIdleTimer->reset();
-    }
-
     // Touch event will boost the refresh rate to performance.
-    // Clear Layer History to get fresh FPS detection
-    if (mLayerHistory) {
+    // Clear Layer History to get fresh FPS detection.
+    // NOTE: Instead of checking all the layers, we should be checking the layer
+    // that is currently on top. b/142507166 will give us this capability.
+    if (mLayerHistory && !mLayerHistory->hasClientSpecifiedFrameRate()) {
         mLayerHistory->clear();
+
+        if (mTouchTimer) {
+            mTouchTimer->reset();
+        }
+
+        if (mSupportKernelTimer && mIdleTimer) {
+            mIdleTimer->reset();
+        }
     }
 }
 
@@ -529,25 +535,31 @@
         return mRefreshRateConfigs.getCurrentRefreshRate().configId;
     }
 
-    // If Display Power is not in normal operation we want to be in performance mode.
-    // When coming back to normal mode, a grace period is given with DisplayPowerTimer
-    if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
-    }
+    // If the layer history doesn't have the frame rate specified, use the old path. NOTE:
+    // if we remove the kernel idle timer, and use our internal idle timer, this code will have to
+    // be refactored.
+    if (!mLayerHistory->hasClientSpecifiedFrameRate()) {
+        // If Display Power is not in normal operation we want to be in performance mode.
+        // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+        if (!mFeatures.isDisplayPowerStateNormal ||
+            mFeatures.displayPowerTimer == TimerState::Reset) {
+            return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        }
 
-    // As long as touch is active we want to be in performance mode
-    if (mFeatures.touch == TouchState::Active) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
-    }
+        // As long as touch is active we want to be in performance mode
+        if (mFeatures.touch == TouchState::Active) {
+            return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        }
 
-    // If timer has expired as it means there is no new content on the screen
-    if (mFeatures.idleTimer == TimerState::Expired) {
-        return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
-    }
+        // If timer has expired as it means there is no new content on the screen
+        if (mFeatures.idleTimer == TimerState::Expired) {
+            return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
+        }
 
-    // If content detection is off we choose performance as we don't know the content fps
-    if (mFeatures.contentDetection == ContentDetectionState::Off) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        // If content detection is off we choose performance as we don't know the content fps
+        if (mFeatures.contentDetection == ContentDetectionState::Off) {
+            return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+        }
     }
 
     // Content detection is on, find the appropriate refresh rate with minimal error
@@ -595,3 +607,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
index fb5414f..27120be 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "SchedulerUtils.h"
 
 #include <cinttypes>
@@ -36,3 +40,6 @@
 
 } // namespace scheduler
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 56b3252..a6fb3a4 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -39,6 +39,14 @@
     virtual ~VSyncDispatch();
 
     /*
+     * A callback that can be registered to be awoken at a given time relative to a vsync event.
+     * \param [in] vsyncTime The timestamp of the vsync the callback is for.
+     * \param [in] targetWakeupTime The timestamp of intended wakeup time of the cb.
+     *
+     */
+    using Callback = std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime)>;
+
+    /*
      * Registers a callback that will be called at designated points on the vsync timeline.
      * The callback can be scheduled, rescheduled targeting vsync times, or cancelled.
      * The token returned must be cleaned up via unregisterCallback.
@@ -51,7 +59,7 @@
      *                          invocation of callbackFn.
      *
      */
-    virtual CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
+    virtual CallbackToken registerCallback(Callback const& callbackFn,
                                            std::string callbackName) = 0;
 
     /*
@@ -112,7 +120,7 @@
  */
 class VSyncCallbackRegistration {
 public:
-    VSyncCallbackRegistration(VSyncDispatch&, std::function<void(nsecs_t)> const& callbackFn,
+    VSyncCallbackRegistration(VSyncDispatch&, VSyncDispatch::Callback const& callbackFn,
                               std::string const& callbackName);
     VSyncCallbackRegistration(VSyncCallbackRegistration&&);
     VSyncCallbackRegistration& operator=(VSyncCallbackRegistration&&);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 48f2abb..2e5b6e9 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -29,7 +29,7 @@
 TimeKeeper::~TimeKeeper() = default;
 
 VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name,
-                                                           std::function<void(nsecs_t)> const& cb,
+                                                           VSyncDispatch::Callback const& cb,
                                                            nsecs_t minVsyncDistance)
       : mName(name),
         mCallback(cb),
@@ -97,13 +97,13 @@
     return *mLastDispatchTime;
 }
 
-void VSyncDispatchTimerQueueEntry::callback(nsecs_t t) {
+void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) {
     {
         std::lock_guard<std::mutex> lk(mRunningMutex);
         mRunning = true;
     }
 
-    mCallback(t);
+    mCallback(vsyncTimestamp, wakeupTimestamp);
 
     std::lock_guard<std::mutex> lk(mRunningMutex);
     mRunning = false;
@@ -171,7 +171,8 @@
 void VSyncDispatchTimerQueue::timerCallback() {
     struct Invocation {
         std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
-        nsecs_t timestamp;
+        nsecs_t vsyncTimestamp;
+        nsecs_t wakeupTimestamp;
     };
     std::vector<Invocation> invocations;
     {
@@ -186,7 +187,7 @@
             if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
                 callback->executing();
                 invocations.emplace_back(
-                        Invocation{callback, *callback->lastExecutedVsyncTarget()});
+                        Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
             }
         }
 
@@ -195,12 +196,12 @@
     }
 
     for (auto const& invocation : invocations) {
-        invocation.callback->callback(invocation.timestamp);
+        invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp);
     }
 }
 
 VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
-        std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) {
+        Callback const& callbackFn, std::string callbackName) {
     std::lock_guard<decltype(mMutex)> lk(mMutex);
     return CallbackToken{
             mCallbacks
@@ -271,7 +272,7 @@
 }
 
 VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
-                                                     std::function<void(nsecs_t)> const& callbackFn,
+                                                     VSyncDispatch::Callback const& callbackFn,
                                                      std::string const& callbackName)
       : mDispatch(dispatch),
         mToken(dispatch.registerCallback(callbackFn, callbackName)),
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 0c9b4fe..087acc7 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -36,7 +36,7 @@
     // Valid transition: disarmed -> armed ( when scheduled )
     // Valid transition: armed -> running -> disarmed ( when timer is called)
     // Valid transition: armed -> disarmed ( when cancelled )
-    VSyncDispatchTimerQueueEntry(std::string const& name, std::function<void(nsecs_t)> const& fn,
+    VSyncDispatchTimerQueueEntry(std::string const& name, VSyncDispatch::Callback const& fn,
                                  nsecs_t minVsyncDistance);
     std::string_view name() const;
 
@@ -62,14 +62,14 @@
     nsecs_t executing();
     // End: functions that are not threadsafe.
 
-    // Invoke the callback with the timestamp, moving the state from running->disarmed.
-    void callback(nsecs_t timestamp);
+    // Invoke the callback with the two given timestamps, moving the state from running->disarmed.
+    void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp);
     // Block calling thread while the callback is executing.
     void ensureNotRunning();
 
 private:
     std::string const mName;
-    std::function<void(nsecs_t)> const mCallback;
+    VSyncDispatch::Callback const mCallback;
 
     nsecs_t mWorkDuration;
     nsecs_t mEarliestVsync;
@@ -104,8 +104,7 @@
                                      nsecs_t timerSlack, nsecs_t minVsyncDistance);
     ~VSyncDispatchTimerQueue();
 
-    CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
-                                   std::string callbackName) final;
+    CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
     void unregisterCallback(CallbackToken token) final;
     ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
     CancelResult cancel(CallbackToken token) final;
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 8de35b1..40a992c 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "VSyncModulator.h"
@@ -144,3 +148,6 @@
 }
 
 } // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 3b99a58..e8c47a5 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 #include "VSyncPredictor.h"
@@ -38,7 +42,7 @@
         kMinimumSamplesForPrediction(minimumSamplesForPrediction),
         kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
         mIdealPeriod(idealPeriod) {
-    mRateMap[mIdealPeriod] = {idealPeriod, 0};
+    resetModel();
 }
 
 inline size_t VSyncPredictor::next(int i) const {
@@ -199,6 +203,10 @@
         mRateMap[mIdealPeriod] = {period, 0};
     }
 
+    clearTimestamps();
+}
+
+void VSyncPredictor::clearTimestamps() {
     if (!timestamps.empty()) {
         mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
         timestamps.clear();
@@ -223,4 +231,13 @@
     return needsMoreSamples;
 }
 
+void VSyncPredictor::resetModel() {
+    std::lock_guard<std::mutex> lk(mMutex);
+    mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
+    clearTimestamps();
+}
+
 } // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 4210b3c..41e5469 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -40,6 +40,7 @@
     void addVsyncTimestamp(nsecs_t timestamp) final;
     nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final;
     nsecs_t currentPeriod() const final;
+    void resetModel() final;
 
     /*
      * Inform the model that the period is anticipated to change to a new value.
@@ -48,7 +49,7 @@
      *
      * \param [in] period   The new period that should be used.
      */
-    void setPeriod(nsecs_t period);
+    void setPeriod(nsecs_t period) final;
 
     /* Query if the model is in need of more samples to make a prediction at timePoint.
      * \param [in] timePoint    The timePoint to inquire of.
@@ -61,6 +62,7 @@
 private:
     VSyncPredictor(VSyncPredictor const&) = delete;
     VSyncPredictor& operator=(VSyncPredictor const&) = delete;
+    void clearTimestamps() REQUIRES(mMutex);
 
     size_t const kHistorySize;
     size_t const kMinimumSamplesForPrediction;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 158a184..53fa212 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
 #define LOG_TAG "VSyncReactor"
 //#define LOG_NDEBUG 0
 #include "VSyncReactor.h"
 #include <log/log.h>
+#include <utils/Trace.h>
 #include "TimeKeeper.h"
 #include "VSyncDispatch.h"
 #include "VSyncTracker.h"
@@ -48,7 +50,8 @@
                      nsecs_t period, nsecs_t offset, nsecs_t notBefore)
           : mCallback(cb),
             mRegistration(dispatch,
-                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1),
+                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
+                                    std::placeholders::_2),
                           std::string(name)),
             mPeriod(period),
             mOffset(offset),
@@ -85,15 +88,13 @@
     }
 
 private:
-    void callback(nsecs_t vsynctime) {
-        nsecs_t period = 0;
+    void callback(nsecs_t vsynctime, nsecs_t wakeupTime) {
         {
             std::lock_guard<std::mutex> lk(mMutex);
-            period = mPeriod;
             mLastCallTime = vsynctime;
         }
 
-        mCallback->onDispSyncEvent(vsynctime - period);
+        mCallback->onDispSyncEvent(wakeupTime);
 
         {
             std::lock_guard<std::mutex> lk(mMutex);
@@ -187,6 +188,7 @@
 }
 
 void VSyncReactor::setPeriod(nsecs_t period) {
+    ATRACE_INT64("VSR-setPeriod", period);
     std::lock_guard lk(mMutex);
     mLastHwVsync.reset();
     if (period == getPeriod()) {
@@ -200,7 +202,9 @@
     return mTracker->currentPeriod();
 }
 
-void VSyncReactor::beginResync() {}
+void VSyncReactor::beginResync() {
+    mTracker->resetModel();
+}
 
 void VSyncReactor::endResync() {}
 
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 6be63fe..2b27884 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -61,6 +61,9 @@
      */
     virtual void setPeriod(nsecs_t period) = 0;
 
+    /* Inform the tracker that the samples it has are not accurate for prediction. */
+    virtual void resetModel() = 0;
+
 protected:
     VSyncTracker(VSyncTracker const&) = delete;
     VSyncTracker& operator=(VSyncTracker const&) = delete;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 65d02ad..6d18922 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
@@ -334,6 +338,14 @@
     mLayerTripleBufferingDisabled = atoi(value);
     ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
 
+    property_get("ro.surface_flinger.supports_background_blur", value, "0");
+    bool supportsBlurs = atoi(value);
+    property_get("debug.sf.disableBlurs", value, "0");
+    bool disableBlurs = atoi(value);
+    mEnableBlurs = supportsBlurs && !disableBlurs;
+    ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs,
+             disableBlurs);
+
     const size_t defaultListSize = MAX_LAYERS;
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
@@ -490,6 +502,7 @@
     ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
 
     mFrameTracer->initialize();
+    mTimeStats->onBootFinished();
 
     // wait patiently for the window manager death
     const String16 name("window");
@@ -576,6 +589,7 @@
                 .setUseColorManagerment(useColorManagement)
                 .setEnableProtectedContext(enable_protected_contents(false))
                 .setPrecacheToneMapperShaderOnly(false)
+                .setSupportsBackgroundBlur(mEnableBlurs)
                 .setContextPriority(useContextPriority
                         ? renderengine::RenderEngine::ContextPriority::HIGH
                         : renderengine::RenderEngine::ContextPriority::MEDIUM)
@@ -871,7 +885,7 @@
         repaintEverythingForHWC();
         // Start receiving vsync samples now, so that we can detect a period
         // switch.
-        mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+        mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod);
         // As we called to set period, we will call to onRefreshRateChangeCompleted once
         // DispSync model is locked.
         mVSyncModulator->onRefreshRateChangeInitiated();
@@ -948,9 +962,9 @@
     mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
     mDesiredActiveConfigChanged = false;
 
-    mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
-    auto refreshRate =
+    auto const refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
+    mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod);
     mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
     mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
 }
@@ -1747,12 +1761,6 @@
                 mGpuFrameMissedCount++;
             }
 
-            mScheduler->chooseRefreshRateForContent();
-
-            if (performSetActiveConfig()) {
-                break;
-            }
-
             if (frameMissed && mPropagateBackpressure) {
                 if ((hwcFrameMissed && !gpuFrameMissed) ||
                     mPropagateBackpressureClientComposition) {
@@ -1769,6 +1777,13 @@
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
 
+            // Layers need to get updated (in the previous line) before we can use them for
+            // choosing the refresh rate.
+            mScheduler->chooseRefreshRateForContent();
+            if (performSetActiveConfig()) {
+                break;
+            }
+
             updateCursorAsync();
             updateInputFlinger();
 
@@ -3374,6 +3389,9 @@
         if (layer->setCornerRadius(s.cornerRadius))
             flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eBackgroundBlurRadiusChanged) {
+        if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
+    }
     if (what & layer_state_t::eLayerStackChanged) {
         ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
         // We only allow setting layer stacks for top level layers,
@@ -3474,6 +3492,14 @@
     if (what & layer_state_t::eShadowRadiusChanged) {
         if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eFrameRateSelectionPriority) {
+        if (privileged && layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) {
+            flags |= eTraversalNeeded;
+        }
+    }
+    if (what & layer_state_t::eFrameRateChanged) {
+        if (layer->setFrameRate(s.frameRate)) flags |= eTraversalNeeded;
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
@@ -4277,13 +4303,8 @@
         rootProto->add_children(offscreenLayer->sequence);
 
         // Add layer
-        LayerProto* layerProto = layersProto.add_layers();
-        offscreenLayer->writeToProtoDrawingState(layerProto, traceFlags);
-        offscreenLayer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing,
-                                                traceFlags);
+        LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
         layerProto->set_parent(offscreenRootLayerId);
-
-        offscreenLayer->writeToProto(layersProto, traceFlags);
     }
 }
 
@@ -4512,7 +4533,6 @@
         case ENABLE_VSYNC_INJECTIONS:
         case GET_ANIMATION_FRAME_STATS:
         case GET_HDR_CAPABILITIES:
-        case SET_ACTIVE_CONFIG:
         case SET_DESIRED_DISPLAY_CONFIG_SPECS:
         case GET_DESIRED_DISPLAY_CONFIG_SPECS:
         case SET_ACTIVE_COLOR_MODE:
@@ -5777,3 +5797,6 @@
 #if defined(__gl2_h_)
 #error "don't include gl2/gl2.h in this file"
 #endif
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 723e332..7f7d8da 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -445,7 +445,6 @@
                                        bool* outSupported) const override;
     void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
     void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
-    status_t setActiveConfig(const sp<IBinder>& displayToken, int id) override;
     status_t clearAnimationFrameStats() override;
     status_t getAnimationFrameStats(FrameStats* outStats) const override;
     status_t getHdrCapabilities(const sp<IBinder>& displayToken,
@@ -538,6 +537,7 @@
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
     void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
+    status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
     // Once HWC has returned the present fence, this sets the active config and a new refresh
     // rate in SF.
     void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -1025,6 +1025,7 @@
     const std::shared_ptr<TimeStats> mTimeStats;
     const std::unique_ptr<FrameTracer> mFrameTracer;
     bool mUseHwcVirtualDisplays = false;
+    bool mEnableBlurs = false;
     std::atomic<uint32_t> mFrameMissedCount = 0;
     std::atomic<uint32_t> mHwcFrameMissedCount = 0;
     std::atomic<uint32_t> mGpuFrameMissedCount = 0;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index d5c2306..e12d31a 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <compositionengine/impl/CompositionEngine.h>
 #include <cutils/properties.h>
 #include <ui/GraphicBuffer.h>
@@ -138,3 +142,6 @@
 }
 
 } // namespace android::surfaceflinger
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 9b1f658..3997b04 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "SurfaceFlinger.h"
 #include "SurfaceFlingerDefaultFactory.h"
 
@@ -26,3 +30,6 @@
 }
 
 } // namespace android::surfaceflinger
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 8e0462a..6884b4c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -13,6 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
 #undef LOG_TAG
 #define LOG_TAG "SurfaceInterceptor"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -110,6 +114,7 @@
     addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
     addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
     addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
+    addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
     if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
         addDeferTransactionLocked(transaction, layerId,
                                   layer->mCurrentState.barrierLayer_legacy.promote(),
@@ -318,6 +323,13 @@
     cornerRadiusChange->set_corner_radius(cornerRadius);
 }
 
+void SurfaceInterceptor::addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
+                                                       int32_t backgroundBlurRadius) {
+    SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+    BackgroundBlurRadiusChange* blurRadiusChange(change->mutable_background_blur_radius());
+    blurRadiusChange->set_background_blur_radius(backgroundBlurRadius);
+}
+
 void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
         const sp<const Layer>& layer, uint64_t frameNumber)
 {
@@ -418,6 +430,9 @@
     if (state.what & layer_state_t::eCornerRadiusChanged) {
         addCornerRadiusLocked(transaction, layerId, state.cornerRadius);
     }
+    if (state.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+        addBackgroundBlurRadiusLocked(transaction, layerId, state.backgroundBlurRadius);
+    }
     if (state.what & layer_state_t::eDeferTransaction_legacy) {
         sp<Layer> otherLayer = nullptr;
         if (state.barrierHandle_legacy != nullptr) {
@@ -677,3 +692,6 @@
 
 } // namespace impl
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index c6f9e8a..a665f62 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -152,6 +152,8 @@
     void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
     void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
     void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
+    void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
+                                       int32_t backgroundBlurRadius);
     void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
             const sp<const Layer>& layer, uint64_t frameNumber);
     void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index eb26cd0..6fd4e46 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -13,6 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
 #undef LOG_TAG
 #define LOG_TAG "SurfaceTracing"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -202,3 +206,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 2080a38..d27fbb4 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -1,12 +1,35 @@
-cc_library_static {
+cc_library_shared {
     name: "libtimestats",
-    defaults: ["surfaceflinger_defaults"],
     srcs: [
-      "TimeStats.cpp",
+        "TimeStats.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libprotobuf-cpp-lite",
+        "libprotoutil",
+        "libstatslog",
+        "libstatspull",
+        "libstatssocket",
+        "libtimestats_proto",
+        "libui",
+        "libutils",
     ],
     export_include_dirs: ["."],
-    shared_libs: [
-      "libtimestats_proto",
-      "libui",
+    export_shared_lib_headers: [
+        "libprotoutil",
+        "libstatslog",
+        "libstatspull",
+        "libstatssocket",
+        "libtimestats_proto",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
     ],
 }
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index a5fabf2..7c824ec 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -13,6 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
 #undef LOG_TAG
 #define LOG_TAG "TimeStats"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -20,6 +24,7 @@
 #include "TimeStats.h"
 
 #include <android-base/stringprintf.h>
+#include <android/util/ProtoOutputStream.h>
 #include <log/log.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
@@ -32,11 +37,142 @@
 
 namespace impl {
 
-TimeStats::TimeStats() {
+status_pull_atom_return_t TimeStats::pullAtomCallback(int32_t atom_tag,
+                                                      pulled_stats_event_list* data, void* cookie) {
+    impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
+    if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
+        return timeStats->populateGlobalAtom(data);
+    } else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
+        return timeStats->populateLayerAtom(data);
+    }
+
+    return STATS_PULL_SKIP;
+}
+
+status_pull_atom_return_t TimeStats::populateGlobalAtom(pulled_stats_event_list* data) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (mTimeStats.statsStart == 0) {
+        return STATS_PULL_SKIP;
+    }
+    flushPowerTimeLocked();
+
+    struct stats_event* event = mStatsDelegate->addStatsEventToPullData(data);
+    mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
+    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+    mStatsDelegate->statsEventBuild(event);
+    clearGlobalLocked();
+
+    return STATS_PULL_SUCCESS;
+}
+
+namespace {
+// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
+const std::array<std::string, 6> kHistogramNames = {
+        "present2present", "post2present",    "acquire2present",
+        "latch2present",   "desired2present", "post2acquire",
+};
+
+std::string histogramToProtoByteString(const std::unordered_map<int32_t, int32_t>& histogram,
+                                       size_t maxPulledHistogramBuckets) {
+    auto buckets = std::vector<std::pair<int32_t, int32_t>>(histogram.begin(), histogram.end());
+    std::sort(buckets.begin(), buckets.end(),
+              [](std::pair<int32_t, int32_t>& left, std::pair<int32_t, int32_t>& right) {
+                  return left.second > right.second;
+              });
+
+    util::ProtoOutputStream proto;
+    int histogramSize = 0;
+    for (const auto& bucket : buckets) {
+        if (++histogramSize > maxPulledHistogramBuckets) {
+            break;
+        }
+        proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+                            1 /* field id */,
+                    (int32_t)bucket.first);
+        proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+                            2 /* field id */,
+                    (int64_t)bucket.second);
+    }
+
+    std::string byteString;
+    proto.serializeToString(&byteString);
+    return byteString;
+}
+} // namespace
+
+status_pull_atom_return_t TimeStats::populateLayerAtom(pulled_stats_event_list* data) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
+    for (const auto& ele : mTimeStats.stats) {
+        dumpStats.push_back(&ele.second);
+    }
+
+    std::sort(dumpStats.begin(), dumpStats.end(),
+              [](TimeStatsHelper::TimeStatsLayer const* l,
+                 TimeStatsHelper::TimeStatsLayer const* r) {
+                  return l->totalFrames > r->totalFrames;
+              });
+
+    if (mMaxPulledLayers < dumpStats.size()) {
+        dumpStats.resize(mMaxPulledLayers);
+    }
+
+    for (const auto& layer : dumpStats) {
+        struct stats_event* event = mStatsDelegate->addStatsEventToPullData(data);
+        mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
+        mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
+        mStatsDelegate->statsEventWriteInt64(event, layer->totalFrames);
+        mStatsDelegate->statsEventWriteInt64(event, layer->droppedFrames);
+
+        for (const auto& name : kHistogramNames) {
+            const auto& histogram = layer->deltas.find(name);
+            if (histogram == layer->deltas.cend()) {
+                mStatsDelegate->statsEventWriteByteArray(event, nullptr, 0);
+            } else {
+                std::string bytes = histogramToProtoByteString(histogram->second.hist,
+                                                               mMaxPulledHistogramBuckets);
+                mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)bytes.c_str(),
+                                                         bytes.size());
+            }
+        }
+
+        mStatsDelegate->statsEventBuild(event);
+    }
+    clearLayersLocked();
+
+    return STATS_PULL_SUCCESS;
+}
+
+TimeStats::TimeStats() : TimeStats(nullptr, std::nullopt, std::nullopt) {}
+
+TimeStats::TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
+                     std::optional<size_t> maxPulledLayers,
+                     std::optional<size_t> maxPulledHistogramBuckets) {
+    if (statsDelegate != nullptr) {
+        mStatsDelegate = std::move(statsDelegate);
+    }
+
+    if (maxPulledLayers) {
+        mMaxPulledLayers = *maxPulledLayers;
+    }
+
+    if (maxPulledHistogramBuckets) {
+        mMaxPulledHistogramBuckets = *maxPulledHistogramBuckets;
+    }
+}
+
+void TimeStats::onBootFinished() {
     // Temporarily enable TimeStats by default. Telemetry is disabled while
     // we move onto statsd, so TimeStats is currently not exercised at all
-    // during testing.
-    // TODO: remove this.
+    // during testing without enabling by default.
+    // TODO: remove this, as we should only be paying this overhead on devices
+    // where statsd exists.
     enable();
 }
 
@@ -65,7 +201,7 @@
     }
 
     if (argsMap.count("-clear")) {
-        clear();
+        clearAll();
     }
 
     if (argsMap.count("-enable")) {
@@ -590,6 +726,10 @@
     mEnabled.store(true);
     mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
     mPowerTime.prevTime = systemTime();
+    mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                                  TimeStats::pullAtomCallback, nullptr, this);
+    mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                                  TimeStats::pullAtomCallback, nullptr, this);
     ALOGD("Enabled");
 }
 
@@ -602,15 +742,21 @@
     flushPowerTimeLocked();
     mEnabled.store(false);
     mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mStatsDelegate->unregisterStatsPullAtomCallback(
+            android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+    mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
     ALOGD("Disabled");
 }
 
-void TimeStats::clear() {
+void TimeStats::clearAll() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    clearGlobalLocked();
+    clearLayersLocked();
+}
+
+void TimeStats::clearGlobalLocked() {
     ATRACE_CALL();
 
-    std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStatsTracker.clear();
-    mTimeStats.stats.clear();
     mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
     mTimeStats.statsEnd = 0;
     mTimeStats.totalFrames = 0;
@@ -624,7 +770,15 @@
     mPowerTime.prevTime = systemTime();
     mGlobalRecord.prevPresentTime = 0;
     mGlobalRecord.presentFences.clear();
-    ALOGD("Cleared");
+    ALOGD("Cleared global stats");
+}
+
+void TimeStats::clearLayersLocked() {
+    ATRACE_CALL();
+
+    mTimeStatsTracker.clear();
+    mTimeStats.stats.clear();
+    ALOGD("Cleared layer stats");
 }
 
 bool TimeStats::isEnabled() {
@@ -657,3 +811,6 @@
 } // namespace impl
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 65e5cf4..cf1c3c6 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -17,6 +17,9 @@
 #pragma once
 
 #include <hardware/hwcomposer_defs.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
 #include <timestatsproto/TimeStatsHelper.h>
 #include <timestatsproto/TimeStatsProtoHeader.h>
 #include <ui/FenceTime.h>
@@ -37,6 +40,10 @@
 public:
     virtual ~TimeStats() = default;
 
+    // Called once boot has been finished to perform additional capabilities,
+    // e.g. registration to statsd.
+    virtual void onBootFinished() = 0;
+
     virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
     virtual bool isEnabled() = 0;
     virtual std::string miniDump() = 0;
@@ -131,6 +138,50 @@
 public:
     TimeStats();
 
+    // Delegate to the statsd service and associated APIs.
+    // Production code may use this class directly, whereas unit test may define
+    // a subclass for ease of testing.
+    class StatsEventDelegate {
+    public:
+        virtual ~StatsEventDelegate() = default;
+        virtual struct stats_event* addStatsEventToPullData(pulled_stats_event_list* data) {
+            return add_stats_event_to_pull_data(data);
+        }
+        virtual void registerStatsPullAtomCallback(int32_t atom_tag,
+                                                   stats_pull_atom_callback_t callback,
+                                                   pull_atom_metadata* metadata, void* cookie) {
+            return register_stats_pull_atom_callback(atom_tag, callback, metadata, cookie);
+        }
+
+        virtual void unregisterStatsPullAtomCallback(int32_t atom_tag) {
+            return unregister_stats_pull_atom_callback(atom_tag);
+        }
+
+        virtual void statsEventSetAtomId(struct stats_event* event, uint32_t atom_id) {
+            return stats_event_set_atom_id(event, atom_id);
+        }
+
+        virtual void statsEventWriteInt64(struct stats_event* event, int64_t field) {
+            return stats_event_write_int64(event, field);
+        }
+
+        virtual void statsEventWriteString8(struct stats_event* event, const char* field) {
+            return stats_event_write_string8(event, field);
+        }
+
+        virtual void statsEventWriteByteArray(struct stats_event* event, const uint8_t* buf,
+                                              size_t numBytes) {
+            return stats_event_write_byte_array(event, buf, numBytes);
+        }
+
+        virtual void statsEventBuild(struct stats_event* event) { return stats_event_build(event); }
+    };
+    // For testing only for injecting custom dependencies.
+    TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
+              std::optional<size_t> maxPulledLayers,
+              std::optional<size_t> maxPulledHistogramBuckets);
+
+    void onBootFinished() override;
     void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
     bool isEnabled() override;
     std::string miniDump() override;
@@ -167,6 +218,10 @@
     static const size_t MAX_NUM_TIME_RECORDS = 64;
 
 private:
+    static status_pull_atom_return_t pullAtomCallback(int32_t atom_tag,
+                                                      pulled_stats_event_list* data, void* cookie);
+    status_pull_atom_return_t populateGlobalAtom(pulled_stats_event_list* data);
+    status_pull_atom_return_t populateLayerAtom(pulled_stats_event_list* data);
     bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
     void flushAvailableRecordsToStatsLocked(int32_t layerId);
     void flushPowerTimeLocked();
@@ -174,7 +229,9 @@
 
     void enable();
     void disable();
-    void clear();
+    void clearAll();
+    void clearGlobalLocked();
+    void clearLayersLocked();
     void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result);
 
     std::atomic<bool> mEnabled = false;
@@ -187,6 +244,9 @@
 
     static const size_t MAX_NUM_LAYER_RECORDS = 200;
     static const size_t MAX_NUM_LAYER_STATS = 200;
+    std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
+    size_t mMaxPulledLayers = 8;
+    size_t mMaxPulledHistogramBuckets = 6;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 1475889..daa67ae 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "TransactionCompletedThread"
@@ -355,3 +359,6 @@
       : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index ef27847..8fce0c9 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -106,6 +106,7 @@
     layer.refreshPending = layerProto.refresh_pending();
     layer.isProtected = layerProto.is_protected();
     layer.cornerRadius = layerProto.corner_radius();
+    layer.backgroundBlurRadius = layerProto.background_blur_radius();
     for (const auto& entry : layerProto.metadata()) {
         const std::string& dataStr = entry.second;
         std::vector<uint8_t>& outData = layer.metadata.mMap[entry.first];
@@ -290,6 +291,7 @@
     StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
     StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
     StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
+    StringAppendF(&result, "backgroundBlurRadius=%1d, ", backgroundBlurRadius);
     StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
                   static_cast<double>(color.r), static_cast<double>(color.g),
                   static_cast<double>(color.b), static_cast<double>(color.a), flags);
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 774b0e1..52b9165 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -110,6 +110,7 @@
         bool refreshPending;
         bool isProtected;
         float cornerRadius;
+        int backgroundBlurRadius;
         LayerMetadata metadata;
         LayerProtoParser::FloatRect cornerRadiusCrop;
         float shadowRadius;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 41ecafa..8afe503 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -104,6 +104,8 @@
   ColorTransformProto color_transform = 50;
 
   bool is_relative_of = 51;
+  // Layer's background blur radius in pixels.
+  int32 background_blur_radius = 52;
 }
 
 message PositionProto {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index e7986d3..d7ad9de 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <sys/resource.h>
 
 #include <sched.h>
@@ -121,3 +125,6 @@
 
     return 0;
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 049c872..ed2b220 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -371,3 +371,12 @@
     access: Readonly
     prop_name: "ro.surface_flinger.support_kernel_idle_timer"
 }
+
+# Indicates whether background blurs are supported.
+prop {
+    api_name: "supports_background_blur"
+    type: Boolean
+    scope: Public
+    access: Readonly
+    prop_name: "ro.surface_flinger.supports_background_blur"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 2d52507..d24ad18 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -104,6 +104,10 @@
     prop_name: "ro.surface_flinger.support_kernel_idle_timer"
   }
   prop {
+    api_name: "supports_background_blur"
+    prop_name: "ro.surface_flinger.supports_background_blur"
+  }
+  prop {
     api_name: "use_color_management"
     prop_name: "ro.surface_flinger.use_color_management"
   }
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 0403237..94ebe89 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -32,6 +32,7 @@
         "MirrorLayer_test.cpp",
         "MultiDisplayLayerBounds_test.cpp",
         "RelativeZ_test.cpp",
+        "SetFrameRate_test.cpp",
         "SetGeometry_test.cpp",
         "Stress_test.cpp",
         "SurfaceInterceptor_test.cpp",
@@ -55,7 +56,6 @@
         "liblog",
         "libnativewindow",
         "libprotobuf-cpp-full",
-        "libtimestats_proto",
         "libui",
         "libutils",
     ],
@@ -68,7 +68,7 @@
     name: "ipc_defaults",
     cflags: [
         "-Wall",
-	"-Werror",
+        "-Werror",
     ],
 }
 
@@ -82,11 +82,11 @@
     ],
     cppflags: [
         "-Wall",
-	"-Werror",
-	"-Wformat",
-	"-Wthread-safety",
-	"-Wunused",
-	"-Wunreachable-code",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
     ],
     shared_libs: [
         "libandroid",
@@ -98,7 +98,6 @@
         "liblayers_proto",
         "liblog",
         "libprotobuf-cpp-full",
-        "libtimestats_proto",
         "libui",
         "libutils",
     ],
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 8ddda60..293738c 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 
@@ -379,3 +383,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f618873..f339ab0 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -31,6 +31,10 @@
  * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
  * return anything meaningful.
  */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
 class CredentialsTest : public ::testing::Test {
 protected:
     void SetUp() override {
@@ -214,10 +218,17 @@
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
 }
 
-TEST_F(CredentialsTest, SetActiveConfigTest) {
+TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
+    int32_t defaultConfig;
+    float minFps;
+    float maxFps;
+    status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+                                                                       &minFps, &maxFps);
+    ASSERT_EQ(res, NO_ERROR);
     std::function<status_t()> condition = [=]() {
-        return SurfaceComposerClient::setActiveConfig(display, 0);
+        return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps,
+                                                                   maxFps);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
@@ -362,3 +373,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
index 0cef0d1..46b98f9 100644
--- a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
+++ b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 namespace android {
 
@@ -67,3 +71,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index d51b9a1..3aa4474 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <thread>
 #include "LayerTransactionTest.h"
 namespace android {
@@ -68,3 +72,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 7a5ed48..6d28e62 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 #include "utils/CallbackUtils.h"
 
@@ -870,3 +874,6 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 92698f0..24874b0 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gui/BufferItemConsumer.h>
 #include <ui/Transform.h>
 #include <thread>
@@ -1841,3 +1845,6 @@
     }
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 7816c66..97cba63 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <private/android_filesystem_config.h>
 #include <thread>
 #include "LayerTransactionTest.h"
@@ -190,3 +194,6 @@
     ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index daeff17..3bbd12a 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <cutils/properties.h>
 #include <gui/BufferItemConsumer.h>
 #include "TransactionTestHarnesses.h"
 
@@ -239,6 +244,41 @@
         shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
     }
 }
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.surface_flinger.supports_background_blur", value, "0");
+    if (!atoi(value)) {
+        // This device doesn't support blurs, no-op.
+        return;
+    }
+
+    auto size = 256;
+    auto center = size / 2;
+    auto blurRadius = 50;
+
+    sp<SurfaceControl> backgroundLayer;
+    ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+    sp<SurfaceControl> leftLayer;
+    ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+    sp<SurfaceControl> blurLayer;
+    ASSERT_NO_FATAL_FAILURE(blurLayer = createLayer("blur", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(blurLayer, Color::TRANSPARENT, size, size));
+
+    Transaction().setBackgroundBlurRadius(blurLayer, blurRadius).apply();
+
+    auto shot = getScreenCapture();
+    // Edges are mixed
+    shot->expectColor(Rect(center - 1, center - 5, center, center + 5), Color{150, 150, 0, 255},
+                      50 /* tolerance */);
+    shot->expectColor(Rect(center, center - 5, center + 1, center + 5), Color{150, 150, 0, 255},
+                      50 /* tolerance */);
+}
+
 TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
     sp<SurfaceControl> bufferLayer;
     ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
@@ -267,3 +307,6 @@
     }
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 42ec34a..7e9202b 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gui/BufferItemConsumer.h>
 #include "TransactionTestHarnesses.h"
 
@@ -186,3 +190,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 0ad122b..0459386 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 
 namespace android {
@@ -1708,3 +1712,6 @@
     ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index 0bcac1a..b49bd54 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 
 namespace android {
@@ -224,3 +228,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 066c9aa..e525e2a 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 
 namespace android {
@@ -122,3 +126,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index 8c56d27..1180cac 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 
 namespace android {
@@ -204,3 +208,6 @@
     }
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
new file mode 100644
index 0000000..fc65263
--- /dev/null
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <system/window.h>
+
+#include <thread>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetFrameRateTest : public LayerTransactionTest {
+protected:
+    void TearDown() {
+        mLayer = nullptr;
+        LayerTransactionTest::TearDown();
+    }
+
+    void CreateLayer(uint32_t layerType) {
+        ASSERT_EQ(nullptr, mLayer.get());
+        mLayerType = layerType;
+        ASSERT_NO_FATAL_FAILURE(mLayer = createLayer("TestLayer", mLayerWidth, mLayerHeight,
+                                                     /*flags=*/mLayerType));
+        ASSERT_NE(nullptr, mLayer.get());
+    }
+
+    void PostBuffers(const Color& color) {
+        auto startTime = systemTime();
+        while (systemTime() - startTime < s2ns(1)) {
+            ASSERT_NO_FATAL_FAILURE(
+                    fillLayerColor(mLayerType, mLayer, color, mLayerWidth, mLayerHeight));
+            std::this_thread::sleep_for(100ms);
+        }
+    }
+
+    const int mLayerWidth = 32;
+    const int mLayerHeight = 32;
+    sp<SurfaceControl> mLayer;
+    uint32_t mLayerType;
+};
+
+TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
+    CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
+    native_window_set_frame_rate(mLayer->getSurface().get(), 100.f);
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+    Transaction().setFrameRate(mLayer, 200.f).apply();
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+    native_window_set_frame_rate(mLayer->getSurface().get(), 300.f);
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+}
+
+TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
+    CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
+    Transaction().setFrameRate(mLayer, 400.f).apply();
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
index dca06ec..5fe2513 100644
--- a/services/surfaceflinger/tests/SetGeometry_test.cpp
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "LayerTransactionTest.h"
 
 namespace android {
@@ -97,3 +101,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index ee857b0..e9b6ba0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gtest/gtest.h>
 
 #include <gui/SurfaceComposerClient.h>
@@ -107,3 +111,6 @@
 }
 
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 1fa426d..4a2ab7c 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
@@ -49,6 +53,7 @@
 constexpr int32_t RELATIVE_Z = 42;
 constexpr float ALPHA_UPDATE = 0.29f;
 constexpr float CORNER_RADIUS_UPDATE = 0.2f;
+constexpr int BACKGROUND_BLUR_RADIUS_UPDATE = 24;
 constexpr float POSITION_UPDATE = 121;
 const Rect CROP_UPDATE(16, 16, 32, 32);
 const float SHADOW_RADIUS_UPDATE = 35.0f;
@@ -179,6 +184,8 @@
     bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
     bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
     bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
+    bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+                                         bool foundBackgroundBlurRadius);
     bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
     bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
     bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -216,6 +223,7 @@
     void layerUpdate(Transaction&);
     void cropUpdate(Transaction&);
     void cornerRadiusUpdate(Transaction&);
+    void backgroundBlurRadiusUpdate(Transaction&);
     void matrixUpdate(Transaction&);
     void overrideScalingModeUpdate(Transaction&);
     void transparentRegionHintUpdate(Transaction&);
@@ -351,6 +359,10 @@
     t.setCornerRadius(mBGSurfaceControl, CORNER_RADIUS_UPDATE);
 }
 
+void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) {
+    t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
+}
+
 void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
     t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
 }
@@ -428,6 +440,7 @@
     runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
     runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
     runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
+    runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
     runInTransaction(&SurfaceInterceptorTest::layerUpdate);
     runInTransaction(&SurfaceInterceptorTest::cropUpdate);
     runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
@@ -505,6 +518,18 @@
     return foundCornerRadius;
 }
 
+bool SurfaceInterceptorTest::backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+                                                             bool foundBackgroundBlur) {
+    bool hasBackgroundBlur(change.background_blur_radius().background_blur_radius() ==
+                           BACKGROUND_BLUR_RADIUS_UPDATE);
+    if (hasBackgroundBlur && !foundBackgroundBlur) {
+        foundBackgroundBlur = true;
+    } else if (hasBackgroundBlur && foundBackgroundBlur) {
+        []() { FAIL(); }();
+    }
+    return foundBackgroundBlur;
+}
+
 bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
     bool hasLayer(change.layer().layer() == LAYER_UPDATE);
     if (hasLayer && !foundLayer) {
@@ -701,6 +726,9 @@
                         case SurfaceChange::SurfaceChangeCase::kCornerRadius:
                             foundUpdate = cornerRadiusUpdateFound(change, foundUpdate);
                             break;
+                        case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
+                            foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
+                            break;
                         case SurfaceChange::SurfaceChangeCase::kMatrix:
                             foundUpdate = matrixUpdateFound(change, foundUpdate);
                             break;
@@ -883,6 +911,11 @@
             SurfaceChange::SurfaceChangeCase::kCornerRadius);
 }
 
+TEST_F(SurfaceInterceptorTest, InterceptBackgroundBlurRadiusUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate,
+                SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
+}
+
 TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
     captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
 }
@@ -1011,3 +1044,6 @@
     ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
 }
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 31837a9..ff403f6 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -29,7 +29,7 @@
         "liblog",
         "libnativewindow",
         "libsync",
-        "libtimestats_proto",
+        "libtimestats",
         "libui",
         "libutils",
     ],
@@ -38,7 +38,6 @@
         "libgmock",
         "libperfetto_client_experimental",
         "librenderengine",
-        "libtimestats",
         "libtrace_proto",
     ],
     header_libs: [
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 0c370a6..1d3fed8 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeComposer"
@@ -776,6 +780,15 @@
     return V2_4::Error::UNSUPPORTED;
 }
 
+V2_4::Error FakeComposerClient::validateDisplay_2_4(
+        Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+        std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+        uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+        std::vector<uint32_t>* /*outRequestMasks*/,
+        IComposerClient::ClientTargetProperty* /*outClientTargetProperty*/) {
+    return V2_4::Error::NONE;
+}
+
 //////////////////////////////////////////////////////////////////
 
 void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
@@ -896,3 +909,6 @@
     // this might get more involving.
     return static_cast<Layer>(index);
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index f9ff2bf..a524850 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -251,6 +251,12 @@
             Display display,
             std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
     V2_4::Error setContentType(Display display, IComposerClient::ContentType type) override;
+    V2_4::Error validateDisplay_2_4(
+            Display display, std::vector<Layer>* outChangedLayers,
+            std::vector<IComposerClient::Composition>* outCompositionTypes,
+            uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+            std::vector<uint32_t>* outRequestMasks,
+            IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
 
     void setClient(ComposerClient* client);
 
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
index f727bc4..c656eed 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeHwcService"
@@ -170,3 +174,6 @@
 }
 
 } // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 4d21468..2f89696 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeHwcUtil"
@@ -183,3 +187,6 @@
 }
 
 } // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 09fdbdf..6874f6f 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeHwcTest"
@@ -433,7 +437,10 @@
 
         for (int i = 0; i < configs.size(); i++) {
             if (configs[i].w == 800u) {
-                EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              configs[i].fps,
+                                                                              configs[i].fps));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
@@ -531,7 +538,10 @@
 
         for (int i = 0; i < configs.size(); i++) {
             if (configs[i].fps == 1e9f / 11'111'111) {
-                EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              configs[i].fps,
+                                                                              configs[i].fps));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
@@ -639,7 +649,10 @@
 
         for (int i = 0; i < configs.size(); i++) {
             if (configs[i].w == 800u && configs[i].fps == 1e9f / 11'111'111) {
-                EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              configs[i].fps,
+                                                                              configs[i].fps));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
@@ -679,7 +692,10 @@
 
         for (int i = 0; i < configs.size(); i++) {
             if (configs[i].fps == 1e9f / 8'333'333) {
-                EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              configs[i].fps,
+                                                                              configs[i].fps));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
@@ -719,7 +735,10 @@
 
         for (int i = 0; i < configs.size(); i++) {
             if (configs[i].w == 1600 && configs[i].fps == 1e9f / 11'111'111) {
-                EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setActiveConfig(display, i));
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              configs[i].fps,
+                                                                              configs[i].fps));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
@@ -1970,3 +1989,6 @@
     ::testing::InitGoogleMock(&argc, argv);
     return RUN_ALL_TESTS();
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 13774b4..f9a1fe9 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <array>
 #include <unordered_set>
 #include <unordered_map>
@@ -4770,3 +4774,6 @@
     ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
             virtualDisplayExceptions));
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index 6484562..fcd0d31 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <mutex>
 #include <array>
 #include <sstream>
@@ -789,3 +793,6 @@
 
     return 0;
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
index 90127a1..b76ace8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
@@ -13,6 +13,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <sstream>
 #include <gtest/gtest.h>
 
@@ -279,3 +283,6 @@
 
     return optimized;
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
index 904b927..8ca8815 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <sstream>
 #include <android/hardware/graphics/common/1.0/types.h>
 
@@ -111,3 +115,6 @@
     }
     return stream.str();
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
index c5b92d0..1efb21e 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <sstream>
 #include <cutils/log.h>
 #include <ui/Rect.h>
@@ -780,3 +784,6 @@
 const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{
     false,   true,    true,    false,   true,    true,
 }};
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 68adbfc..1eaf2dd 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -49,6 +49,7 @@
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
         "RefreshRateConfigsTest.cpp",
+        "RefreshRateSelectionTest.cpp",
         "RefreshRateStatsTest.cpp",
         "RegionSamplingTest.cpp",
         "TimeStatsTest.cpp",
@@ -79,11 +80,14 @@
         "libgui_mocks",
         "libperfetto_client_experimental",
         "librenderengine_mocks",
-        "libtimestats",
         "perfetto_trace_protos",
     ],
     shared_libs: [
+        "libprotoutil",
+        "libstatssocket",
         "libsurfaceflinger",
+        "libtimestats",
+        "libtimestats_proto",
     ],
     header_libs: [
         "libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 74ce540..1b8c76d 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "CachingTest"
 
@@ -91,3 +95,6 @@
     }
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index cce21ce..8a762d4 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "CompositionTest"
 
@@ -1423,3 +1427,6 @@
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 55c3ab8..9680a17 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
@@ -21,6 +25,7 @@
 
 #include <compositionengine/Display.h>
 #include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/mock/DisplaySurface.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -1274,6 +1279,243 @@
 }
 
 /* ------------------------------------------------------------------------
+ * DisplayDevice::setProjection
+ */
+
+class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
+public:
+    static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
+    static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false;
+    static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true;
+    static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080;  // arbitrary
+    static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
+
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_0 = 0;
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_90 = HAL_TRANSFORM_ROT_90;
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_180 = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V;
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_270 =
+            HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+
+    DisplayDeviceSetProjectionTest(ui::Size flingerDisplaySize, ui::Size hardwareDisplaySize,
+                                   ui::Rotation physicalOrientation)
+          : mFlingerDisplaySize(flingerDisplaySize),
+            mHardwareDisplaySize(hardwareDisplaySize),
+            mPhysicalOrientation(physicalOrientation),
+            mDisplayDevice(createDisplayDevice()) {}
+
+    sp<DisplayDevice> createDisplayDevice() {
+        // The DisplayDevice is required to have a framebuffer (behind the
+        // ANativeWindow interface) which uses the actual hardware display
+        // size.
+        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.width), Return(0)));
+        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.height), Return(0)));
+        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
+        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
+        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
+        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT));
+
+        return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL,
+                                         DEFAULT_DISPLAY_IS_PRIMARY)
+                .setNativeWindow(mNativeWindow)
+                .setPhysicalOrientation(mPhysicalOrientation)
+                .inject();
+    }
+
+    ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+
+    void setProjectionForRotation0() {
+        // A logical rotation of 0 uses the SurfaceFlinger display size
+        mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
+                                      Rect(mFlingerDisplaySize));
+    }
+
+    void setProjectionForRotation90() {
+        // A logical rotation of 90 uses the SurfaceFlinger display size with
+        // the width/height swapped.
+        mDisplayDevice->setProjection(ui::ROTATION_90, Rect(SwapWH(mFlingerDisplaySize)),
+                                      Rect(SwapWH(mFlingerDisplaySize)));
+    }
+
+    void setProjectionForRotation180() {
+        // A logical rotation of 180 uses the SurfaceFlinger display size
+        mDisplayDevice->setProjection(ui::ROTATION_180, Rect(mFlingerDisplaySize),
+                                      Rect(mFlingerDisplaySize));
+    }
+
+    void setProjectionForRotation270() {
+        // A logical rotation of 270 uses the SurfaceFlinger display size with
+        // the width/height swapped.
+        mDisplayDevice->setProjection(ui::ROTATION_270, Rect(SwapWH(mFlingerDisplaySize)),
+                                      Rect(SwapWH(mFlingerDisplaySize)));
+    }
+
+    void expectStateForHardwareTransform0() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    void expectStateForHardwareTransform90() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+        // For 90, the frame and viewport have the hardware display size width and height swapped
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    void expectStateForHardwareTransform180() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    void expectStateForHardwareTransform270() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+        // For 270, the frame and viewport have the hardware display size width and height swapped
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    const ui::Size mFlingerDisplaySize;
+    const ui::Size mHardwareDisplaySize;
+    const ui::Rotation mPhysicalOrientation;
+    const sp<DisplayDevice> mDisplayDevice;
+};
+
+struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed0()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_0) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform270();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed90()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_90) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform0();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed180()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_180) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform90();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed270()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_270) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform180();
+}
+
+/* ------------------------------------------------------------------------
  * SurfaceFlinger::getDisplayNativePrimaries
  */
 
@@ -3239,3 +3481,6 @@
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
index c334bcf..68cb52f 100644
--- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
@@ -394,3 +398,6 @@
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index f055fe7..ca51cb6 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LayerHistoryTest"
 
@@ -64,6 +84,7 @@
 TEST_F(LayerHistoryTest, oneLayer) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
 
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
@@ -90,6 +111,7 @@
 TEST_F(LayerHistoryTest, oneHDRLayer) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
 
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
@@ -109,6 +131,7 @@
 TEST_F(LayerHistoryTest, explicitTimestamp) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
 
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
@@ -130,8 +153,13 @@
     auto layer3 = createLayer();
 
     EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+
     EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+
     EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
 
     nsecs_t time = mTime;
 
@@ -241,3 +269,6 @@
 
 } // namespace
 } // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
index 6360ec1..910e73b 100644
--- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -124,3 +128,6 @@
 } // namespace
 } // namespace scheduler
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index cc3c985..86aa8fb 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -242,11 +242,11 @@
 TEST_F(RefreshRateConfigsTest, testInPolicy) {
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60_POINT_4, HWC_GROUP_ID_0,
                                          "60fps", 60};
-    ASSERT_TRUE(expectedDefaultConfig.inPolicy(60.000004, 60.000004));
+    ASSERT_TRUE(expectedDefaultConfig.inPolicy(60.000004f, 60.000004f));
     ASSERT_TRUE(expectedDefaultConfig.inPolicy(59.0f, 60.1f));
-    ASSERT_FALSE(expectedDefaultConfig.inPolicy(75.0, 90.0));
-    ASSERT_FALSE(expectedDefaultConfig.inPolicy(60.0011, 90.0));
-    ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0, 59.998));
+    ASSERT_FALSE(expectedDefaultConfig.inPolicy(75.0f, 90.0f));
+    ASSERT_FALSE(expectedDefaultConfig.inPolicy(60.0011f, 90.0f));
+    ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f));
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
new file mode 100644
index 0000000..cffdc14
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "Layer.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+/**
+ * This class covers all the test that are related to refresh rate selection.
+ */
+class RefreshRateSelectionTest : public testing::Test {
+public:
+    RefreshRateSelectionTest();
+    ~RefreshRateSelectionTest() override;
+
+protected:
+    static constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+    static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+    static constexpr uint32_t WIDTH = 100;
+    static constexpr uint32_t HEIGHT = 100;
+    static constexpr uint32_t LAYER_FLAGS = 0;
+    static constexpr int32_t PRIORITY_UNSET = -1;
+
+    void setupScheduler();
+    void setupComposer(int virtualDisplayCount);
+    sp<BufferQueueLayer> createBufferQueueLayer();
+    sp<BufferStateLayer> createBufferStateLayer();
+    sp<ColorLayer> createColorLayer();
+
+    void setParent(Layer* child, Layer* parent);
+    void commitTransaction(Layer* layer);
+
+    TestableSurfaceFlinger mFlinger;
+    Hwc2::mock::Composer* mComposer = nullptr;
+
+    sp<Client> mClient;
+    sp<Layer> mParent;
+    sp<Layer> mChild;
+    sp<Layer> mGrandChild;
+};
+
+RefreshRateSelectionTest::RefreshRateSelectionTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+    setupScheduler();
+    setupComposer(0);
+}
+
+RefreshRateSelectionTest::~RefreshRateSelectionTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+sp<BufferQueueLayer> RefreshRateSelectionTest::createBufferQueueLayer() {
+    sp<Client> client;
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+                           LAYER_FLAGS, LayerMetadata());
+    return new BufferQueueLayer(args);
+}
+
+sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() {
+    sp<Client> client;
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+                           LAYER_FLAGS, LayerMetadata());
+    return new BufferStateLayer(args);
+}
+
+sp<ColorLayer> RefreshRateSelectionTest::createColorLayer() {
+    sp<Client> client;
+    LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+                           LayerMetadata());
+    return new ColorLayer(args);
+}
+
+void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
+    child->setParent(parent);
+}
+
+void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
+    layer->commitTransaction(layer->getCurrentState());
+}
+
+void RefreshRateSelectionTest::setupScheduler() {
+    auto eventThread = std::make_unique<mock::EventThread>();
+    auto sfEventThread = std::make_unique<mock::EventThread>();
+
+    EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*eventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+    EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+    EXPECT_CALL(*primaryDispSync, getPeriod())
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+    EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+    mFlinger.setupScheduler(std::move(primaryDispSync),
+                            std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+                            std::move(sfEventThread));
+}
+
+void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) {
+    mComposer = new Hwc2::mock::Composer();
+    EXPECT_CALL(*mComposer, getCapabilities())
+            .WillOnce(Return(std::vector<IComposer::Capability>()));
+    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+    Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferQueueLayers) {
+    mParent = createBufferQueueLayer();
+    mChild = createBufferQueueLayer();
+    setParent(mChild.get(), mParent.get());
+    mGrandChild = createBufferQueueLayer();
+    setParent(mGrandChild.get(), mChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child has its own priority.
+    mGrandChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child inherits from his parent.
+    mChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Grandchild inherits from his grand parent.
+    mParent->setFrameRateSelectionPriority(1);
+    commitTransaction(mParent.get());
+    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) {
+    mParent = createBufferStateLayer();
+    mChild = createBufferStateLayer();
+    setParent(mChild.get(), mParent.get());
+    mGrandChild = createBufferStateLayer();
+    setParent(mGrandChild.get(), mChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child has its own priority.
+    mGrandChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child inherits from his parent.
+    mChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Grandchild inherits from his grand parent.
+    mParent->setFrameRateSelectionPriority(1);
+    commitTransaction(mParent.get());
+    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) {
+    mParent = createColorLayer();
+    mChild = createColorLayer();
+    setParent(mChild.get(), mParent.get());
+    mGrandChild = createColorLayer();
+    setParent(mGrandChild.get(), mChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child has its own priority.
+    mGrandChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child inherits from his parent.
+    mChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Grandchild inherits from his grand parent.
+    mParent->setFrameRateSelectionPriority(1);
+    commitTransaction(mParent.get());
+    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+} // namespace
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index ef4699f..8e07c79 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -195,3 +199,6 @@
 } // namespace
 } // namespace scheduler
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index d8de804..f19e554 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "RegionSamplingTest"
 
@@ -137,3 +141,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 40536ab..b1ecf4d 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -144,3 +164,6 @@
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
index 5865579..5f6a715 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -128,4 +132,6 @@
 
 } // namespace
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9728c80..8ddb872 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -605,6 +605,11 @@
             return *this;
         }
 
+        auto& setPhysicalOrientation(ui::Rotation orientation) {
+            mCreationArgs.physicalOrientation = orientation;
+            return *this;
+        }
+
         sp<DisplayDevice> inject() {
             DisplayDeviceState state;
             state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 3e808c0..5044626 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -14,10 +14,15 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
 #include <TimeStats/TimeStats.h>
+#include <android/util/ProtoOutputStream.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
@@ -36,8 +41,12 @@
 namespace android {
 namespace {
 
+using testing::_;
+using testing::AnyNumber;
 using testing::Contains;
+using testing::InSequence;
 using testing::SizeIs;
+using testing::StrEq;
 using testing::UnorderedElementsAre;
 
 // clang-format off
@@ -132,7 +141,42 @@
     }
 
     std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
-    std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
+
+    class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
+    public:
+        FakeStatsEventDelegate() = default;
+        ~FakeStatsEventDelegate() override = default;
+
+        struct stats_event* addStatsEventToPullData(pulled_stats_event_list*) override {
+            return mEvent;
+        }
+        void registerStatsPullAtomCallback(int32_t atom_tag, stats_pull_atom_callback_t callback,
+                                           pull_atom_metadata*, void* cookie) override {
+            mAtomTags.push_back(atom_tag);
+            mCallback = callback;
+            mCookie = cookie;
+        }
+
+        status_pull_atom_return_t makePullAtomCallback(int32_t atom_tag, void* cookie) {
+            return (*mCallback)(atom_tag, nullptr, cookie);
+        }
+
+        MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t));
+        MOCK_METHOD2(statsEventSetAtomId, void(struct stats_event*, uint32_t));
+        MOCK_METHOD2(statsEventWriteInt64, void(struct stats_event*, int64_t));
+        MOCK_METHOD2(statsEventWriteString8, void(struct stats_event*, const char*));
+        MOCK_METHOD3(statsEventWriteByteArray, void(struct stats_event*, const uint8_t*, size_t));
+        MOCK_METHOD1(statsEventBuild, void(struct stats_event*));
+
+        struct stats_event* mEvent = stats_event_obtain();
+        std::vector<int32_t> mAtomTags;
+        stats_pull_atom_callback_t mCallback = nullptr;
+        void* mCookie = nullptr;
+    };
+    FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
+    std::unique_ptr<TimeStats> mTimeStats =
+            std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+                                              std::nullopt, std::nullopt);
 };
 
 std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -209,14 +253,26 @@
     return distr(mRandomEngine);
 }
 
-TEST_F(TimeStatsTest, enabledByDefault) {
+TEST_F(TimeStatsTest, disabledByDefault) {
+    ASSERT_FALSE(mTimeStats->isEnabled());
+}
+
+TEST_F(TimeStatsTest, enabledAfterBoot) {
+    mTimeStats->onBootFinished();
     ASSERT_TRUE(mTimeStats->isEnabled());
 }
 
 TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
     ASSERT_TRUE(mTimeStats->isEnabled());
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
 
+    EXPECT_CALL(*mDelegate,
+                unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+    EXPECT_CALL(*mDelegate,
+                unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
     EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
     ASSERT_FALSE(mTimeStats->isEnabled());
 }
@@ -627,6 +683,319 @@
     ASSERT_EQ(0, globalProto.stats_size());
 }
 
+TEST_F(TimeStatsTest, globalStatsCallback) {
+    constexpr size_t TOTAL_FRAMES = 5;
+    constexpr size_t MISSED_FRAMES = 4;
+    constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+
+    mTimeStats->onBootFinished();
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+        mTimeStats->incrementTotalFrames();
+    }
+    for (size_t i = 0; i < MISSED_FRAMES; i++) {
+        mTimeStats->incrementMissedFrames();
+    }
+    for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+        mTimeStats->incrementClientCompositionFrames();
+    }
+
+    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventSetAtomId(mDelegate->mEvent,
+                                        android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+        EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+    }
+    EXPECT_EQ(STATS_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                              mDelegate->mCookie));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    EXPECT_EQ(0, globalProto.total_frames());
+    EXPECT_EQ(0, globalProto.missed_frames());
+    EXPECT_EQ(0, globalProto.client_composition_frames());
+    EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
+namespace {
+std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
+                                             const std::vector<int32_t>& frameCounts) {
+    util::ProtoOutputStream proto;
+    for (int i = 0; i < times.size(); i++) {
+        ALOGE("Writing time: %d", times[i]);
+        proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
+                    (int32_t)times[i]);
+        ALOGE("Writing count: %d", frameCounts[i]);
+        proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
+                    (int64_t)frameCounts[i]);
+    }
+    std::string byteString;
+    proto.serializeToString(&byteString);
+    return byteString;
+}
+
+std::string dumpByteStringHex(const std::string& str) {
+    std::stringstream ss;
+    ss << std::hex;
+    for (const char& c : str) {
+        ss << (int)c << " ";
+    }
+
+    return ss.str();
+}
+
+} // namespace
+
+MATCHER_P2(BytesEq, bytes, size, "") {
+    std::string expected;
+    expected.append((const char*)bytes, size);
+    std::string actual;
+    actual.append((const char*)arg, size);
+
+    *result_listener << "Bytes are not equal! \n";
+    *result_listener << "size: " << size << "\n";
+    *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
+    *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
+
+    return expected == actual;
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
+    std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
+    std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
+    std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
+    std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
+    std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventSetAtomId(mDelegate->mEvent,
+                                        android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteString8(mDelegate->mEvent,
+                                           StrEq(genLayerName(LAYER_ID_0).c_str())));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedPresentToPresent.c_str(),
+                                                     expectedPresentToPresent.size()),
+                                             expectedPresentToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
+                                                     expectedPostToPresent.size()),
+                                             expectedPostToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedAcquireToPresent.c_str(),
+                                                     expectedAcquireToPresent.size()),
+                                             expectedAcquireToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
+                                                     expectedLatchToPresent.size()),
+                                             expectedLatchToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedDesiredToPresent.c_str(),
+                                                     expectedDesiredToPresent.size()),
+                                             expectedDesiredToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
+                                                     expectedPostToAcquire.size()),
+                                             expectedPostToAcquire.size()));
+        EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+    }
+    EXPECT_EQ(STATS_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    EXPECT_EQ(0, globalProto.stats_size());
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_CALL(*mDelegate,
+                statsEventSetAtomId(mDelegate->mEvent,
+                                    android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+            .Times(2);
+    EXPECT_CALL(*mDelegate,
+                statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
+    EXPECT_CALL(*mDelegate,
+                statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+    EXPECT_EQ(STATS_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+    // Now make sure that TimeStats flushes global stats to register the
+    // callback.
+    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedPresentToPresent.c_str(),
+                                                     expectedPresentToPresent.size()),
+                                             expectedPresentToPresent.size()));
+        EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+                .Times(AnyNumber());
+    }
+    EXPECT_EQ(STATS_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
+    mDelegate = new FakeStatsEventDelegate;
+    mTimeStats =
+            std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+                                              std::nullopt, 1);
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedPresentToPresent.c_str(),
+                                                     expectedPresentToPresent.size()),
+                                             expectedPresentToPresent.size()));
+        EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+                .Times(AnyNumber());
+    }
+    EXPECT_EQ(STATS_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
+    mDelegate = new FakeStatsEventDelegate;
+    mTimeStats =
+            std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
+                                              std::nullopt);
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_CALL(*mDelegate,
+                statsEventSetAtomId(mDelegate->mEvent,
+                                    android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+            .Times(1);
+    EXPECT_CALL(*mDelegate,
+                statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+    EXPECT_EQ(STATS_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
 TEST_F(TimeStatsTest, canSurviveMonkey) {
     if (g_noSlowTests) {
         GTEST_SKIP();
@@ -656,3 +1025,6 @@
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 994a509..f1739e5 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "CompositionTest"
 
@@ -321,3 +325,6 @@
     EXPECT_EQ(nullptr, ret.get());
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 5846c77..acf852d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -50,6 +50,7 @@
     nsecs_t currentPeriod() const final { return mPeriod; }
 
     void setPeriod(nsecs_t) final {}
+    void resetModel() final {}
 
 private:
     nsecs_t const mPeriod;
@@ -83,6 +84,7 @@
     }
 
     void setPeriod(nsecs_t) final {}
+    void resetModel() final {}
 
 private:
     std::mutex mutable mMutex;
@@ -101,7 +103,7 @@
     RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl)
           : mWorkload(wl),
             mCallback(
-                    dispatch, [&](auto time) { callback_called(time); }, "repeat0") {}
+                    dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {}
 
     void repeatedly_schedule(size_t iterations, std::function<void(nsecs_t)> const& onEachFrame) {
         mCallbackTimes.reserve(iterations);
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 5aff429..70c9225 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 #define LOG_NDEBUG 0
@@ -41,6 +45,7 @@
     MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(resetModel, void());
 
     nsecs_t nextVSyncTime(nsecs_t timePoint) const {
         if (timePoint % mPeriod == 0) {
@@ -97,13 +102,14 @@
     CountingCallback(VSyncDispatch& dispatch)
           : mDispatch(dispatch),
             mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
-                                                       std::placeholders::_1),
+                                                       std::placeholders::_1,
+                                                       std::placeholders::_2),
                                              "test")) {}
     ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
 
     operator VSyncDispatch::CallbackToken() const { return mToken; }
 
-    void counter(nsecs_t time) { mCalls.push_back(time); }
+    void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
 
     VSyncDispatch& mDispatch;
     VSyncDispatch::CallbackToken mToken;
@@ -115,7 +121,8 @@
     PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
           : mDispatch(dispatch),
             mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
-                                                       std::placeholders::_1),
+                                                       std::placeholders::_1,
+                                                       std::placeholders::_2),
                                              "test")),
             mRegistered(true),
             mPauseAmount(pauseAmount) {}
@@ -123,7 +130,7 @@
 
     operator VSyncDispatch::CallbackToken() const { return mToken; }
 
-    void pause(nsecs_t) {
+    void pause(nsecs_t, nsecs_t) {
         std::unique_lock<std::mutex> lk(mMutex);
         mPause = true;
         mCv.notify_all();
@@ -462,7 +469,8 @@
     EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
 
     VSyncDispatch::CallbackToken tmp;
-    tmp = mDispatch.registerCallback([&](auto) { mDispatch.schedule(tmp, 100, 2000); }, "o.o");
+    tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
+                                     "o.o");
 
     mDispatch.schedule(tmp, 100, 1000);
     advanceToNextCallback();
@@ -472,7 +480,7 @@
     VSyncDispatch::CallbackToken tmp;
     std::optional<nsecs_t> lastTarget;
     tmp = mDispatch.registerCallback(
-            [&](auto timestamp) {
+            [&](auto timestamp, auto) {
                 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
                           ScheduleResult::Scheduled);
                 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
@@ -621,7 +629,7 @@
     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
 
     VSyncCallbackRegistration cb(
-            mDispatch, [](auto) {}, "");
+            mDispatch, [](auto, auto) {}, "");
     VSyncCallbackRegistration cb1(std::move(cb));
     cb.schedule(100, 1000);
     cb.cancel();
@@ -635,9 +643,9 @@
     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
 
     VSyncCallbackRegistration cb(
-            mDispatch, [](auto) {}, "");
+            mDispatch, [](auto, auto) {}, "");
     VSyncCallbackRegistration cb1(
-            mDispatch, [](auto) {}, "");
+            mDispatch, [](auto, auto) {}, "");
     cb1 = std::move(cb);
     cb.schedule(100, 1000);
     cb.cancel();
@@ -656,7 +664,7 @@
 TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
     std::string name("basicname");
     VSyncDispatchTimerQueueEntry entry(
-            name, [](auto) {}, mVsyncMoveThreshold);
+            name, [](auto, auto) {}, mVsyncMoveThreshold);
     EXPECT_THAT(entry.name(), Eq(name));
     EXPECT_FALSE(entry.lastExecutedVsyncTarget());
     EXPECT_FALSE(entry.wakeupTime());
@@ -664,7 +672,7 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
 
     EXPECT_FALSE(entry.wakeupTime());
     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
@@ -684,7 +692,7 @@
             .Times(1)
             .WillOnce(Return(10000));
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
 
     EXPECT_FALSE(entry.wakeupTime());
     EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
@@ -695,12 +703,14 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
     auto callCount = 0;
-    auto calledTime = 0;
+    auto vsyncCalledTime = 0;
+    auto wakeupCalledTime = 0;
     VSyncDispatchTimerQueueEntry entry(
             "test",
-            [&](auto time) {
+            [&](auto vsyncTime, auto wakeupTime) {
                 callCount++;
-                calledTime = time;
+                vsyncCalledTime = vsyncTime;
+                wakeupCalledTime = wakeupTime;
             },
             mVsyncMoveThreshold);
 
@@ -709,10 +719,11 @@
     ASSERT_TRUE(wakeup);
     EXPECT_THAT(*wakeup, Eq(900));
 
-    entry.callback(entry.executing());
+    entry.callback(entry.executing(), *wakeup);
 
     EXPECT_THAT(callCount, Eq(1));
-    EXPECT_THAT(calledTime, Eq(mPeriod));
+    EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
+    EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
     EXPECT_FALSE(entry.wakeupTime());
     auto lastCalledTarget = entry.lastExecutedVsyncTarget();
     ASSERT_TRUE(lastCalledTarget);
@@ -726,7 +737,7 @@
             .WillOnce(Return(1020));
 
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
 
     EXPECT_FALSE(entry.wakeupTime());
     entry.update(mStubTracker, 0);
@@ -745,7 +756,7 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
     entry.update(mStubTracker, 0);
 
@@ -756,7 +767,7 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
     entry.executing(); // 1000 is executing
     // had 1000 not been executing, this could have been scheduled for time 800.
@@ -773,7 +784,7 @@
 TEST_F(VSyncDispatchTimerQueueEntryTest,
        willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
 
     Sequence seq;
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
@@ -795,7 +806,7 @@
 
 TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
     VSyncDispatchTimerQueueEntry entry(
-            "test", [](auto) {}, mVsyncMoveThreshold);
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
     EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
     EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
@@ -803,3 +814,6 @@
 }
 
 } // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 4cb6a38..6ec3844 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 #define LOG_NDEBUG 0
@@ -351,4 +355,22 @@
     EXPECT_THAT(prediction, Ge(timePoint));
 }
 
+TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
+    auto const idealPeriod = 10000;
+    auto const realPeriod = 10500;
+    tracker.setPeriod(idealPeriod);
+    for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+        tracker.addVsyncTimestamp(i * realPeriod);
+    }
+
+    EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+                IsCloseTo(realPeriod, mMaxRoundingError));
+    tracker.resetModel();
+    EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+                IsCloseTo(idealPeriod, mMaxRoundingError));
+}
+
 } // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 4df20af..ce1fafe 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -39,6 +39,7 @@
     MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(resetModel, void());
 };
 
 class VSyncTrackerWrapper : public VSyncTracker {
@@ -50,7 +51,8 @@
         return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
     }
     nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
-    void setPeriod(nsecs_t period) { mTracker->setPeriod(period); }
+    void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
+    void resetModel() final { mTracker->resetModel(); }
 
 private:
     std::shared_ptr<VSyncTracker> const mTracker;
@@ -73,7 +75,8 @@
 
 class MockVSyncDispatch : public VSyncDispatch {
 public:
-    MOCK_METHOD2(registerCallback, CallbackToken(std::function<void(nsecs_t)> const&, std::string));
+    MOCK_METHOD2(registerCallback,
+                 CallbackToken(std::function<void(nsecs_t, nsecs_t)> const&, std::string));
     MOCK_METHOD1(unregisterCallback, void(CallbackToken));
     MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
     MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
@@ -82,7 +85,7 @@
 class VSyncDispatchWrapper : public VSyncDispatch {
 public:
     VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
-    CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
+    CallbackToken registerCallback(std::function<void(nsecs_t, nsecs_t)> const& callbackFn,
                                    std::string callbackName) final {
         return mDispatch->registerCallback(callbackFn, callbackName);
     }
@@ -159,14 +162,15 @@
     static constexpr nsecs_t mPhase = 3000;
     static constexpr nsecs_t mAnotherPhase = 5200;
     static constexpr nsecs_t period = 10000;
-    static constexpr nsecs_t mFakeCbTime = 2093;
+    static constexpr nsecs_t mFakeVSyncTime = 2093;
+    static constexpr nsecs_t mFakeWakeupTime = 1892;
     static constexpr nsecs_t mFakeNow = 2214;
     static constexpr const char mName[] = "callbacky";
     VSyncDispatch::CallbackToken const mFakeToken{2398};
 
     nsecs_t lastCallbackTime = 0;
     StubCallback outerCb;
-    std::function<void(nsecs_t)> innerCb;
+    std::function<void(nsecs_t, nsecs_t)> innerCb;
 
     VSyncReactor mReactor;
 };
@@ -439,7 +443,8 @@
             .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
     EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
             .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime))
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
             .Times(2)
             .InSequence(seq);
     EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
@@ -447,24 +452,25 @@
 
     mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
     ASSERT_TRUE(innerCb);
-    innerCb(mFakeCbTime);
-    innerCb(mFakeCbTime);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
 }
 
-TEST_F(VSyncReactorTest, callbackTimestampReadapted) {
+TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) {
     Sequence seq;
     EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
             .InSequence(seq)
             .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
     EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
             .InSequence(seq);
-    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime))
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
             .InSequence(seq);
 
     mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
     ASSERT_TRUE(innerCb);
-    innerCb(mFakeCbTime);
-    EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeCbTime - period));
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
+    EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime));
 }
 
 TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
@@ -540,7 +546,7 @@
     mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
     mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
     ASSERT_TRUE(innerCb);
-    innerCb(mFakeCbTime);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
 }
 
 TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
@@ -555,6 +561,11 @@
     mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
 }
 
+TEST_F(VSyncReactorTest, beginResyncResetsModel) {
+    EXPECT_CALL(*mMockTracker, resetModel());
+    mReactor.beginResync();
+}
+
 using VSyncReactorDeathTest = VSyncReactorTest;
 TEST_F(VSyncReactorDeathTest, invalidRemoval) {
     mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
@@ -590,7 +601,7 @@
 
     ON_CALL(*mMockDispatch, schedule(_, _, _))
             .WillByDefault(Return(ScheduleResult::CannotSchedule));
-    EXPECT_DEATH(innerCb(mFakeCbTime), ".*");
+    EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*");
 }
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
index 7ed57b9..0780af1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "mock/DisplayHardware/MockComposer.h"
 
 namespace android {
@@ -27,3 +31,6 @@
 } // namespace mock
 } // namespace Hwc2
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index f375e23..1fd0e61 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -28,6 +28,7 @@
           : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 800, 600, 0, {})) {}
 
     MOCK_CONST_METHOD0(getType, const char*());
+    MOCK_METHOD0(getFrameSelectionPriority, int32_t());
     MOCK_CONST_METHOD0(isVisible, bool());
     MOCK_METHOD0(createClone, sp<Layer>());
 };
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
index 4129328..7e925b9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "mock/MockSurfaceInterceptor.h"
 
 namespace android {
@@ -25,3 +29,6 @@
 
 } // namespace mock
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index ec74a42..9ada5ef 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,6 +28,7 @@
     TimeStats();
     ~TimeStats() override;
 
+    MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
     MOCK_METHOD0(isEnabled, bool());
     MOCK_METHOD0(miniDump, std::string());
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index a1b45e6..667dfb9 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <android/looper.h>
 #include <gui/DisplayEventReceiver.h>
 #include <utils/Looper.h>
@@ -82,3 +86,6 @@
 
     return 0;
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"