Merge "Create controller for Power HAL handles."
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 8637a31..28fdaa4 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -237,6 +237,7 @@
         { OPT,      "events/kmem/rss_stat/enable" },
         { OPT,      "events/kmem/ion_heap_grow/enable" },
         { OPT,      "events/kmem/ion_heap_shrink/enable" },
+        { OPT,      "events/ion/ion_stat/enable" },
     } },
 };
 
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 040ddde..9b2f4a8 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -107,6 +107,8 @@
     chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
     chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
     chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ion/ion_stat/enable
+    chmod 0666 /sys/kernel/tracing/events/ion/ion_stat/enable
     chmod 0666 /sys/kernel/debug/tracing/events/mm_event/mm_event_record/enable
     chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable
     chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_generate/enable
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 8ff4ca6..a5e6c68 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -68,4 +68,9 @@
      * Called when screenshot is taken.
      */
     oneway void onScreenshotTaken(boolean success);
+
+    /**
+     * Called when ui intensive bugreport dumps are finished.
+     */
+    oneway void onUiIntensiveBugreportDumpsFinished(String callingPackage);
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c85c7cf..9ba4819 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -169,6 +169,7 @@
 #define OTA_METADATA_DIR "/metadata/ota"
 #define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
 #define LINKERCONFIG_DIR "/linkerconfig"
+#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
 
 // TODO(narayan): Since this information has to be kept in sync
 // with tombstoned, we should just put it in a common header.
@@ -1612,6 +1613,7 @@
     if (!PropertiesHelper::IsUserBuild()) {
         ds.AddDir(PROFILE_DATA_DIR_CUR, true);
         ds.AddDir(PROFILE_DATA_DIR_REF, true);
+        ds.AddZipEntry(ZIP_ROOT_DIR + PACKAGE_DEX_USE_LIST, PACKAGE_DEX_USE_LIST);
     }
     ds.AddDir(PREREBOOT_DATA_DIR, false);
     add_mountinfo();
@@ -2630,11 +2632,13 @@
 
     if (options_->telephony_only) {
         MaybeTakeEarlyScreenshot();
+        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
         MaybeCheckUserConsent(calling_uid, calling_package);
         DumpstateTelephonyOnly(calling_package);
         DumpstateBoard();
     } else if (options_->wifi_only) {
         MaybeTakeEarlyScreenshot();
+        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
         MaybeCheckUserConsent(calling_uid, calling_package);
         DumpstateWifiOnly();
     } else {
@@ -2643,6 +2647,7 @@
 
         // Take screenshot and get consent only after critical dumpsys has finished.
         MaybeTakeEarlyScreenshot();
+        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
         MaybeCheckUserConsent(calling_uid, calling_package);
 
         // Dump state for the default case. This also drops root.
@@ -2732,6 +2737,19 @@
     TakeScreenshot();
 }
 
+void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
+                                                    const std::string& calling_package) {
+    if (calling_uid == AID_SHELL || !CalledByApi()) {
+        return;
+    }
+    if (listener_ != nullptr) {
+        // Let listener know ui intensive bugreport dumps are finished, then it can do event
+        // handling if required.
+        android::String16 package(calling_package.c_str());
+        listener_->onUiIntensiveBugreportDumpsFinished(package);
+    }
+}
+
 void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) {
     if (calling_uid == AID_SHELL || !CalledByApi()) {
         // No need to get consent for shell triggered dumpstates, or not through
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 498f338..28d8936 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -509,6 +509,9 @@
 
     void MaybeTakeEarlyScreenshot();
 
+    void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
+                                             const std::string& calling_package);
+
     void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package);
 
     // Removes the in progress files output files (tmp file, zip/txt file, screenshot),
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 047a1c3..6f2d754 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -173,6 +173,15 @@
         return binder::Status::ok();
     }
 
+    binder::Status onUiIntensiveBugreportDumpsFinished(const android::String16& callingpackage)
+        override {
+        std::lock_guard <std::mutex> lock(lock_);
+        std::string callingpackageUtf8 = std::string(String8(callingpackage).string());
+        dprintf(out_fd_, "\rCalling package of ui intensive bugreport dumps finished: %s",
+                callingpackageUtf8.c_str());
+        return binder::Status::ok();
+    }
+
     bool getIsFinished() {
         std::lock_guard<std::mutex> lock(lock_);
         return is_finished_;
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 2efb130..9871a3b 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -66,6 +66,8 @@
     MOCK_METHOD1(onError, binder::Status(int32_t error_code));
     MOCK_METHOD0(onFinished, binder::Status());
     MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success));
+    MOCK_METHOD1(onUiIntensiveBugreportDumpsFinished,
+        binder::Status(const android::String16& callingpackage));
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 3c04435..82be007 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -318,6 +318,16 @@
 // Phenotype property name for enabling profiling the boot class path.
 static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
 
+static bool IsBootClassPathProfilingEnable() {
+    std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
+    profile_boot_class_path =
+        server_configurable_flags::GetServerConfigurableFlag(
+            RUNTIME_NATIVE_BOOT_NAMESPACE,
+            PROFILE_BOOT_CLASS_PATH,
+            /*default_value=*/ profile_boot_class_path);
+    return profile_boot_class_path == "true";
+}
+
 class RunDex2Oat : public ExecVHelper {
   public:
     RunDex2Oat(int zip_fd,
@@ -450,14 +460,7 @@
                                                                  ENABLE_JITZYGOTE_IMAGE,
                                                                  /*default_value=*/ "");
 
-        std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
-        profile_boot_class_path =
-            server_configurable_flags::GetServerConfigurableFlag(
-                RUNTIME_NATIVE_BOOT_NAMESPACE,
-                PROFILE_BOOT_CLASS_PATH,
-                /*default_value=*/ profile_boot_class_path);
-
-        if (use_jitzygote_image == "true" || profile_boot_class_path == "true") {
+        if (use_jitzygote_image == "true" || IsBootClassPathProfilingEnable()) {
           boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
         } else {
           boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
@@ -896,7 +899,15 @@
     }
 
     RunProfman profman_merge;
-    profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
+    const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>();
+    const std::vector<std::string>& dex_locations = std::vector<std::string>();
+    profman_merge.SetupMerge(
+            profiles_fd,
+            reference_profile_fd,
+            apk_fds,
+            dex_locations,
+            /* for_snapshot= */ false,
+            IsBootClassPathProfilingEnable());
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2810,7 +2821,13 @@
     }
 
     RunProfman args;
-    args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations, /*for_snapshot=*/true);
+    // This is specifically a snapshot for an app, so don't use boot image profiles.
+    args.SetupMerge(profiles_fd,
+            snapshot_fd,
+            apk_fds,
+            dex_locations,
+            /* for_snapshot= */ true,
+            /* for_boot_image= */ false);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index cbbea12..1f9892a 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -49,14 +49,28 @@
     const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
     const std::string instance = name.substr(firstSlash+1);
 
-    for (const auto& manifest : {
-            vintf::VintfObject::GetDeviceHalManifest(),
-            vintf::VintfObject::GetFrameworkHalManifest()
+    struct ManifestWithDescription {
+        std::shared_ptr<const vintf::HalManifest> manifest;
+        const char* description;
+    };
+    for (const ManifestWithDescription& mwd : {
+            ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
+            ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
         }) {
-        if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) {
+        if (mwd.manifest == nullptr) {
+          LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
+          // note, we explicitly do not retry here, so that we can detect VINTF
+          // or other bugs (b/151696835)
+          continue;
+        }
+        if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+            LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
             return true;
         }
     }
+
+    // Although it is tested, explicitly rebuilding qualified name, in case it
+    // becomes something unexpected.
     LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
                << " in the VINTF manifest.";
     return false;
@@ -72,13 +86,20 @@
 #endif  // !VENDORSERVICEMANAGER
 
 ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {
-#ifndef VENDORSERVICEMANAGER
-    // can process these at any times, don't want to delay first VINTF client
-    std::thread([] {
-        vintf::VintfObject::GetDeviceHalManifest();
-        vintf::VintfObject::GetFrameworkHalManifest();
-    }).detach();
-#endif  // !VENDORSERVICEMANAGER
+// TODO(b/151696835): reenable performance hack when we solve bug, since with
+//     this hack and other fixes, it is unlikely we will see even an ephemeral
+//     failure when the manifest parse fails. The goal is that the manifest will
+//     be read incorrectly and cause the process trying to register a HAL to
+//     fail. If this is in fact an early boot kernel contention issue, then we
+//     will get no failure, and by its absence, be signalled to invest more
+//     effort in re-adding this performance hack.
+// #ifndef VENDORSERVICEMANAGER
+//     // can process these at any times, don't want to delay first VINTF client
+//     std::thread([] {
+//         vintf::VintfObject::GetDeviceHalManifest();
+//         vintf::VintfObject::GetFrameworkHalManifest();
+//     }).detach();
+// #endif  // !VENDORSERVICEMANAGER
 }
 ServiceManager::~ServiceManager() {
     // this should only happen in tests
@@ -547,4 +568,4 @@
     return Status::ok();
 }
 
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/docs/Doxyfile b/docs/Doxyfile
index efa639d..a1bd960 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1621,7 +1621,23 @@
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             = __attribute__(x)=
+PREDEFINED             = \
+    "__ANDROID_API__=10000" \
+    "__BEGIN_DECLS=" \
+    "__END_DECLS=" \
+    "__INTRODUCED_IN(x)=" \
+    "__INTRODUCED_IN_32(x)=" \
+    "__INTRODUCED_IN_64(x)=" \
+    "__RENAME(x)=" \
+    "__RENAME_LDBL(x,y,z)=" \
+    "__printflike(x,y)=" \
+    "__attribute__(x)=" \
+    "__wur=" \
+    "__mallocfunc=" \
+    "__attribute_pure__=" \
+    "__attribute__(x)=" \
+    __ANDROID__ \
+    __BIONIC__ \
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
diff --git a/headers/Android.bp b/headers/Android.bp
index 82bc8a1..5337235 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -17,4 +17,5 @@
         "libutils_headers",
         "libstagefright_foundation_headers",
     ],
+    min_sdk_version: "29",
 }
diff --git a/include/android/trace.h b/include/android/trace.h
index d59690a..dbad6f6 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -115,7 +115,7 @@
 #endif /* __ANDROID_API__ >= 29 */
 
 #ifdef __cplusplus
-};
+}
 #endif
 
 #endif // ANDROID_NATIVE_TRACE_H
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index a258a67..98518e0 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -75,47 +75,48 @@
     // Window types from WindowManager.LayoutParams
     enum {
         FIRST_APPLICATION_WINDOW = 1,
-        TYPE_BASE_APPLICATION   = 1,
-        TYPE_APPLICATION        = 2,
+        TYPE_BASE_APPLICATION = 1,
+        TYPE_APPLICATION = 2,
         TYPE_APPLICATION_STARTING = 3,
         LAST_APPLICATION_WINDOW = 99,
-        FIRST_SUB_WINDOW        = 1000,
-        TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW,
-        TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1,
-        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
-        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
-        TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4,
-        LAST_SUB_WINDOW         = 1999,
-        FIRST_SYSTEM_WINDOW     = 2000,
-        TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW,
-        TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1,
-        TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2,
-        TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3,
-        TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4,
-        TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5,
-        TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6,
-        TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7,
-        TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8,
-        TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9,
-        TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10,
-        TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11,
-        TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
-        TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13,
-        TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14,
-        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
-        TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16,
-        TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+17,
-        TYPE_POINTER            = FIRST_SYSTEM_WINDOW+18,
-        TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
-        TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
-        TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
-        TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
-        TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
-        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
-        TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
-        TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
-        TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+39,
-        LAST_SYSTEM_WINDOW      = 2999,
+        FIRST_SUB_WINDOW = 1000,
+        TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW,
+        TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1,
+        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2,
+        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3,
+        TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4,
+        LAST_SUB_WINDOW = 1999,
+        FIRST_SYSTEM_WINDOW = 2000,
+        TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW,
+        TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1,
+        TYPE_PHONE = FIRST_SYSTEM_WINDOW + 2,
+        TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3,
+        TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW + 4,
+        TYPE_TOAST = FIRST_SYSTEM_WINDOW + 5,
+        TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6,
+        TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7,
+        TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8,
+        TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9,
+        TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10,
+        TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11,
+        TYPE_INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12,
+        TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW + 13,
+        TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14,
+        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15,
+        TYPE_DRAG = FIRST_SYSTEM_WINDOW + 16,
+        TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17,
+        TYPE_POINTER = FIRST_SYSTEM_WINDOW + 18,
+        TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19,
+        TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20,
+        TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21,
+        TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22,
+        TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24,
+        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
+        TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
+        TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
+        TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39,
+        TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
+        LAST_SYSTEM_WINDOW = 2999,
     };
 
     enum {
diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h
new file mode 120000
index 0000000..c2047c0
--- /dev/null
+++ b/include/ui/FatVector.h
@@ -0,0 +1 @@
+../../libs/ui/include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 2518b14..f66673f 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -35,4 +35,5 @@
             enabled: true,
         },
     },
+    min_sdk_version: "29",
 }
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7298282..db4aba8 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -28,6 +28,7 @@
         "libcutils_headers",
         "libutils_headers",
     ],
+    min_sdk_version: "29",
 }
 
 // These interfaces are android-specific implementation unrelated to binder
@@ -152,6 +153,7 @@
     sanitize: {
         misc_undefined: ["integer"],
     },
+    min_sdk_version: "29",
 }
 
 // AIDL interface between libbinder and framework.jar
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 9888b59..dab7ad5 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -205,6 +205,10 @@
  : mTheRealServiceManager(impl)
 {}
 
+// This implementation could be simplified and made more efficient by delegating
+// to waitForService. However, this changes the threading structure in some
+// cases and could potentially break prebuilts. Once we have higher logistical
+// complexity, this could be attempted.
 sp<IBinder> ServiceManagerShim::getService(const String16& name) const
 {
     static bool gSystemBootCompleted = false;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 5f1f682..f07f82a 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1052,12 +1052,22 @@
 
 status_t Parcel::writeString8(const String8& str)
 {
-    status_t err = writeInt32(str.bytes());
-    // only write string if its length is more than zero characters,
-    // as readString8 will only read if the length field is non-zero.
-    // this is slightly different from how writeString16 works.
-    if (str.bytes() > 0 && err == NO_ERROR) {
-        err = write(str.string(), str.bytes()+1);
+    return writeString8(str.string(), str.size());
+}
+
+status_t Parcel::writeString8(const char* str, size_t len)
+{
+    if (str == nullptr) return writeInt32(-1);
+
+    status_t err = writeInt32(len);
+    if (err == NO_ERROR) {
+        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char));
+        if (data) {
+            memcpy(data, str, len);
+            *reinterpret_cast<char*>(data+len) = 0;
+            return NO_ERROR;
+        }
+        err = mError;
     }
     return err;
 }
@@ -2012,37 +2022,39 @@
 
 String8 Parcel::readString8() const
 {
-    String8 retString;
-    status_t status = readString8(&retString);
-    if (status != OK) {
-        // We don't care about errors here, so just return an empty string.
-        return String8();
-    }
-    return retString;
+    size_t len;
+    const char* str = readString8Inplace(&len);
+    if (str) return String8(str, len);
+    ALOGE("Reading a NULL string not supported here.");
+    return String8();
 }
 
 status_t Parcel::readString8(String8* pArg) const
 {
-    int32_t size;
-    status_t status = readInt32(&size);
-    if (status != OK) {
-        return status;
-    }
-    // watch for potential int overflow from size+1
-    if (size < 0 || size >= INT32_MAX) {
-        return BAD_VALUE;
-    }
-    // |writeString8| writes nothing for empty string.
-    if (size == 0) {
+    size_t len;
+    const char* str = readString8Inplace(&len);
+    if (str) {
+        pArg->setTo(str, len);
+        return 0;
+    } else {
         *pArg = String8();
-        return OK;
+        return UNEXPECTED_NULL;
     }
-    const char* str = (const char*)readInplace(size + 1);
-    if (str == nullptr) {
-        return BAD_VALUE;
+}
+
+const char* Parcel::readString8Inplace(size_t* outLen) const
+{
+    int32_t size = readInt32();
+    // watch for potential int overflow from size+1
+    if (size >= 0 && size < INT32_MAX) {
+        *outLen = size;
+        const char* str = (const char*)readInplace(size+1);
+        if (str != nullptr) {
+            return str;
+        }
     }
-    pArg->setTo(str, size);
-    return OK;
+    *outLen = 0;
+    return nullptr;
 }
 
 String16 Parcel::readString16() const
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 97f1aee..b6cfb8e 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -119,6 +119,7 @@
     status_t            writeDouble(double val);
     status_t            writeCString(const char* str);
     status_t            writeString8(const String8& str);
+    status_t            writeString8(const char* str, size_t len);
     status_t            writeString16(const String16& str);
     status_t            writeString16(const std::optional<String16>& str);
     status_t            writeString16(const std::unique_ptr<String16>& str);
@@ -312,6 +313,7 @@
     const char*         readCString() const;
     String8             readString8() const;
     status_t            readString8(String8* pArg) const;
+    const char*         readString8Inplace(size_t* outLen) const;
     String16            readString16() const;
     status_t            readString16(String16* pArg) const;
     status_t            readString16(std::optional<String16>* pArg) const;
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
index 2ede6c4..71e1d3c 100644
--- a/libs/binder/include/binder/ParcelFileDescriptor.h
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -31,8 +31,8 @@
 public:
     ParcelFileDescriptor();
     explicit ParcelFileDescriptor(android::base::unique_fd fd);
-    ParcelFileDescriptor(ParcelFileDescriptor&& other) : mFd(std::move(other.mFd)) { }
-    ParcelFileDescriptor& operator=(ParcelFileDescriptor&& other) = default;
+    ParcelFileDescriptor(ParcelFileDescriptor&& other) noexcept : mFd(std::move(other.mFd)) { }
+    ParcelFileDescriptor& operator=(ParcelFileDescriptor&& other) noexcept = default;
     ~ParcelFileDescriptor() override;
 
     int get() const { return mFd.get(); }
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index b790997..3b1faa8 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -116,7 +116,7 @@
         if (time > max_time_bucket) {
             m_long_transactions++;
         }
-        m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1;
+        m_buckets[min((uint32_t)(time / time_per_bucket), num_buckets - 1)] += 1;
         m_best = min(time, m_best);
         m_worst = max(time, m_worst);
         m_transactions += 1;
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 5eb509c..88752ee 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -22,7 +22,7 @@
 
     shared_libs: [
         "libbinder",
-        "libhidlbase",  // libhwbinder is in here
+        "libhidlbase", // libhwbinder is in here
     ],
 
     export_include_dirs: ["include"],
@@ -31,6 +31,7 @@
         "-Wall",
         "-Werror",
     ],
+    min_sdk_version: "29",
 }
 
 hidl_package_root {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 7f57f5d..7976ecb 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -27,6 +27,7 @@
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.bufferqueue@2.0",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library_shared {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index a8384ac..56591bd 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -19,8 +19,6 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <cutils/properties.h>
-
 #include <gui/BLASTBufferQueue.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/GLConsumer.h>
@@ -95,7 +93,8 @@
     if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
 }
 
-BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
+BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height,
+                                   bool enableTripleBuffering)
       : mSurfaceControl(surface),
         mWidth(width),
         mHeight(height),
@@ -105,8 +104,7 @@
     // explicitly so that dequeueBuffer will block
     mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
 
-    int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0);
-    if (!disableTripleBuffer) {
+    if (enableTripleBuffering) {
         mProducer->setMaxDequeuedBufferCount(2);
     }
     mBufferItemConsumer =
@@ -189,13 +187,13 @@
     mPendingReleaseItem.item = std::move(mSubmitted.front());
     mSubmitted.pop();
 
-    processNextBufferLocked();
+    processNextBufferLocked(false);
 
     mCallbackCV.notify_all();
     decStrong((void*)transactionCallbackThunk);
 }
 
-void BLASTBufferQueue::processNextBufferLocked() {
+void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
     ATRACE_CALL();
     if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
         return;
@@ -209,7 +207,7 @@
     SurfaceComposerClient::Transaction localTransaction;
     bool applyTransaction = true;
     SurfaceComposerClient::Transaction* t = &localTransaction;
-    if (mNextTransaction != nullptr && mUseNextTransaction) {
+    if (mNextTransaction != nullptr && useNextTransaction) {
         t = mNextTransaction;
         mNextTransaction = nullptr;
         applyTransaction = false;
@@ -274,16 +272,14 @@
         while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
             mCallbackCV.wait(_lock);
         }
-        mUseNextTransaction = true;
     }
     // add to shadow queue
     mNumFrameAvailable++;
-    processNextBufferLocked();
+    processNextBufferLocked(true);
 }
 
 void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
     std::lock_guard _lock{mMutex};
-    mUseNextTransaction = false;
     mNextTransaction = t;
 }
 
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index a1803d8..8d80833 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -28,7 +28,6 @@
 
 #include <inttypes.h>
 
-#include <cutils/properties.h>
 #include <cutils/atomic.h>
 
 #include <gui/BufferItem.h>
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 3f4c5da..a7cf39a 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -655,8 +655,9 @@
         }
 
         listener = mCore->mConsumerListener;
-        if (listener != nullptr) {
-            listener->onFrameDetached(mSlots[slot].mGraphicBuffer->getId());
+        auto gb = mSlots[slot].mGraphicBuffer;
+        if (listener != nullptr && gb != nullptr) {
+            listener->onFrameDetached(gb->getId());
         }
         mSlots[slot].mBufferState.detachProducer();
         mCore->mActiveBuffers.erase(slot);
@@ -1120,8 +1121,9 @@
         mCore->mFreeBuffers.push_back(slot);
     }
 
-    if (mCore->mConsumerListener != nullptr) {
-        mCore->mConsumerListener->onFrameCancelled(mSlots[slot].mGraphicBuffer->getId());
+    auto gb = mSlots[slot].mGraphicBuffer;
+    if (mCore->mConsumerListener != nullptr && gb != nullptr) {
+        mCore->mConsumerListener->onFrameCancelled(gb->getId());
     }
     mSlots[slot].mFence = fence;
     mCore->mDequeueCondition.notify_all();
diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp
index ab6f364..5762dab 100644
--- a/libs/gui/DebugEGLImageTracker.cpp
+++ b/libs/gui/DebugEGLImageTracker.cpp
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
-#include <cutils/properties.h>
 #include <gui/DebugEGLImageTracker.h>
 
 #include <cinttypes>
 #include <unordered_map>
 
+using android::base::GetBoolProperty;
 using android::base::StringAppendF;
 
 std::mutex DebugEGLImageTracker::mInstanceLock;
@@ -57,10 +58,7 @@
 DebugEGLImageTracker *DebugEGLImageTracker::getInstance() {
     std::lock_guard lock(mInstanceLock);
     if (mInstance == nullptr) {
-        char value[PROPERTY_VALUE_MAX];
-        property_get("debug.sf.enable_egl_image_tracker", value, "0");
-        const bool enabled = static_cast<bool>(atoi(value));
-
+        const bool enabled = GetBoolProperty("debug.sf.enable_egl_image_tracker", false);
         if (enabled) {
             mInstance = new DebugEGLImageTrackerImpl();
         } else {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 26ae188..6c9fd07 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -929,8 +929,11 @@
     }
 
     virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t defaultConfig, float minRefreshRate,
-                                                  float maxRefreshRate) {
+                                                  int32_t defaultConfig,
+                                                  float primaryRefreshRateMin,
+                                                  float primaryRefreshRateMax,
+                                                  float appRequestRefreshRateMin,
+                                                  float appRequestRefreshRateMax) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -947,14 +950,26 @@
             ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
             return result;
         }
-        result = data.writeFloat(minRefreshRate);
+        result = data.writeFloat(primaryRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write minRefreshRate: %d", result);
+            ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
             return result;
         }
-        result = data.writeFloat(maxRefreshRate);
+        result = data.writeFloat(primaryRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write maxRefreshRate: %d", result);
+            ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result);
+            return result;
+        }
+        result = data.writeFloat(appRequestRefreshRateMin);
+        if (result != NO_ERROR) {
+            ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d",
+                  result);
+            return result;
+        }
+        result = data.writeFloat(appRequestRefreshRateMax);
+        if (result != NO_ERROR) {
+            ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d",
+                  result);
             return result;
         }
 
@@ -969,9 +984,14 @@
 
     virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                   int32_t* outDefaultConfig,
-                                                  float* outMinRefreshRate,
-                                                  float* outMaxRefreshRate) {
-        if (!outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE;
+                                                  float* outPrimaryRefreshRateMin,
+                                                  float* outPrimaryRefreshRateMax,
+                                                  float* outAppRequestRefreshRateMin,
+                                                  float* outAppRequestRefreshRateMax) {
+        if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
+            !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+            return BAD_VALUE;
+        }
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -994,14 +1014,26 @@
             ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
             return result;
         }
-        result = reply.readFloat(outMinRefreshRate);
+        result = reply.readFloat(outPrimaryRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read minRefreshRate: %d", result);
+            ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
             return result;
         }
-        result = reply.readFloat(outMaxRefreshRate);
+        result = reply.readFloat(outPrimaryRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read maxRefreshRate: %d", result);
+            ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result);
+            return result;
+        }
+        result = reply.readFloat(outAppRequestRefreshRateMin);
+        if (result != NO_ERROR) {
+            ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d",
+                  result);
+            return result;
+        }
+        result = reply.readFloat(outAppRequestRefreshRateMax);
+        if (result != NO_ERROR) {
+            ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d",
+                  result);
             return result;
         }
         return reply.readInt32();
@@ -1831,20 +1863,38 @@
                 ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
                 return result;
             }
-            float minRefreshRate;
-            result = data.readFloat(&minRefreshRate);
+            float primaryRefreshRateMin;
+            result = data.readFloat(&primaryRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read minRefreshRate: %d", result);
+                ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d",
+                      result);
                 return result;
             }
-            float maxRefreshRate;
-            result = data.readFloat(&maxRefreshRate);
+            float primaryRefreshRateMax;
+            result = data.readFloat(&primaryRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read maxRefreshRate: %d", result);
+                ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d",
+                      result);
                 return result;
             }
-            result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, minRefreshRate,
-                                                  maxRefreshRate);
+            float appRequestRefreshRateMin;
+            result = data.readFloat(&appRequestRefreshRateMin);
+            if (result != NO_ERROR) {
+                ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d",
+                      result);
+                return result;
+            }
+            float appRequestRefreshRateMax;
+            result = data.readFloat(&appRequestRefreshRateMax);
+            if (result != NO_ERROR) {
+                ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d",
+                      result);
+                return result;
+            }
+            result =
+                    setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+                                                 primaryRefreshRateMax, appRequestRefreshRateMin,
+                                                 appRequestRefreshRateMax);
             if (result != NO_ERROR) {
                 ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
                       "%d",
@@ -1858,11 +1908,16 @@
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> displayToken = data.readStrongBinder();
             int32_t defaultConfig;
-            float minRefreshRate;
-            float maxRefreshRate;
+            float primaryRefreshRateMin;
+            float primaryRefreshRateMax;
+            float appRequestRefreshRateMin;
+            float appRequestRefreshRateMax;
 
-            status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
-                                                           &minRefreshRate, &maxRefreshRate);
+            status_t result =
+                    getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+                                                 &primaryRefreshRateMin, &primaryRefreshRateMax,
+                                                 &appRequestRefreshRateMin,
+                                                 &appRequestRefreshRateMax);
             if (result != NO_ERROR) {
                 ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: "
                       "%d",
@@ -1875,14 +1930,28 @@
                 ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
                 return result;
             }
-            result = reply->writeFloat(minRefreshRate);
+            result = reply->writeFloat(primaryRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write minRefreshRate: %d", result);
+                ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
+                      result);
                 return result;
             }
-            result = reply->writeFloat(maxRefreshRate);
+            result = reply->writeFloat(primaryRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write maxRefreshRate: %d", result);
+                ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d",
+                      result);
+                return result;
+            }
+            result = reply->writeFloat(appRequestRefreshRateMin);
+            if (result != NO_ERROR) {
+                ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d",
+                      result);
+                return result;
+            }
+            result = reply->writeFloat(appRequestRefreshRateMax);
+            if (result != NO_ERROR) {
+                ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d",
+                      result);
                 return result;
             }
             reply->writeInt32(result);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2ac078f..e864327 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1698,22 +1698,26 @@
 
 status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                              int32_t defaultConfig,
-                                                             float minRefreshRate,
-                                                             float maxRefreshRate) {
-    return ComposerService::getComposerService()->setDesiredDisplayConfigSpecs(displayToken,
-                                                                               defaultConfig,
-                                                                               minRefreshRate,
-                                                                               maxRefreshRate);
+                                                             float primaryRefreshRateMin,
+                                                             float primaryRefreshRateMax,
+                                                             float appRequestRefreshRateMin,
+                                                             float appRequestRefreshRateMax) {
+    return ComposerService::getComposerService()
+            ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+                                           primaryRefreshRateMax, appRequestRefreshRateMin,
+                                           appRequestRefreshRateMax);
 }
 
 status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                              int32_t* outDefaultConfig,
-                                                             float* outMinRefreshRate,
-                                                             float* outMaxRefreshRate) {
-    return ComposerService::getComposerService()->getDesiredDisplayConfigSpecs(displayToken,
-                                                                               outDefaultConfig,
-                                                                               outMinRefreshRate,
-                                                                               outMaxRefreshRate);
+                                                             float* outPrimaryRefreshRateMin,
+                                                             float* outPrimaryRefreshRateMax,
+                                                             float* outAppRequestRefreshRateMin,
+                                                             float* outAppRequestRefreshRateMax) {
+    return ComposerService::getComposerService()
+            ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
+                                           outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+                                           outAppRequestRefreshRateMax);
 }
 
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 64c21e0..2320771 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -66,7 +66,9 @@
     : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
 {
 public:
-    BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height);
+    BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height,
+                     bool enableTripleBuffering = true);
+
     sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
         return mProducer;
     }
@@ -90,7 +92,7 @@
     BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs);
     BLASTBufferQueue(const BLASTBufferQueue& rhs);
 
-    void processNextBufferLocked() REQUIRES(mMutex);
+    void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
     Rect computeCrop(const BufferItem& item);
 
     sp<SurfaceControl> mSurfaceControl;
@@ -123,8 +125,6 @@
     sp<BLASTBufferItemConsumer> mBufferItemConsumer;
 
     SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
-
-    bool mUseNextTransaction = false;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 109e28b..d9a0253 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -65,6 +65,7 @@
 
         struct VSync {
             uint32_t count;
+            nsecs_t expectedVSyncTimestamp;
         };
 
         struct Hotplug {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e204285..21ad2b2 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -426,19 +426,36 @@
      */
     virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
 
-    /*
-     * Sets the refresh rate boundaries for display configuration.
-     * For all other parameters, default configuration is used. The index for the default is
-     * corresponding to the configs returned from getDisplayConfigs().
+    /* Sets the refresh rate boundaries for the display.
+     *
+     * The primary refresh rate range represents display manager's general guidance on the display
+     * configs we'll consider when switching refresh rates. Unless we get an explicit signal from an
+     * app, we should stay within this range.
+     *
+     * The app request refresh rate range allows us to consider more display configs when switching
+     * refresh rates. Although we should generally stay within the primary range, specific
+     * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
+     * cause us to go outside the primary range. We never go outside the app request range. The app
+     * request range will be greater than or equal to the primary refresh rate range, never smaller.
+     *
+     * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider
+     * switching between. Only configs with a config group and resolution matching defaultConfig
+     * will be considered for switching. The defaultConfig index corresponds to the list of configs
+     * returned from getDisplayConfigs().
      */
     virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t defaultConfig, float minRefreshRate,
-                                                  float maxRefreshRate) = 0;
+                                                  int32_t defaultConfig,
+                                                  float primaryRefreshRateMin,
+                                                  float primaryRefreshRateMax,
+                                                  float appRequestRefreshRateMin,
+                                                  float appRequestRefreshRateMax) = 0;
 
     virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                   int32_t* outDefaultConfig,
-                                                  float* outMinRefreshRate,
-                                                  float* outMaxRefreshRate) = 0;
+                                                  float* outPrimaryRefreshRateMin,
+                                                  float* outPrimaryRefreshRateMax,
+                                                  float* outAppRequestRefreshRateMin,
+                                                  float* outAppRequestRefreshRateMax) = 0;
     /*
      * Gets whether brightness operations are supported on a display.
      *
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index b1d9d42..fe1094c 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -118,21 +118,19 @@
     // Shorthand for getDisplayConfigs element at getActiveConfig index.
     static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
 
-    // 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().
+    // Sets the refresh rate boundaries for the display.
     static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                 int32_t defaultConfig, float minRefreshRate,
-                                                 float maxRefreshRate);
-    // Gets 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().
-    // The reason is passed in for telemetry tracking, and it corresponds to the list of all
-    // the policy rules that were used.
+                                                 int32_t defaultConfig, float primaryRefreshRateMin,
+                                                 float primaryRefreshRateMax,
+                                                 float appRequestRefreshRateMin,
+                                                 float appRequestRefreshRateMax);
+    // Gets the refresh rate boundaries for the display.
     static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                  int32_t* outDefaultConfig,
-                                                 float* outMinRefreshRate,
-                                                 float* outMaxRefreshRate);
+                                                 float* outPrimaryRefreshRateMin,
+                                                 float* outPrimaryRefreshRateMax,
+                                                 float* outAppRequestRefreshRateMin,
+                                                 float* outAppRequestRefreshRateMax);
 
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index e7f7c1f..64b1eac 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -4,4 +4,7 @@
     api_packages: ["android.sysprop"],
     property_owner: "Platform",
     vendor_available: true,
+    cpp: {
+        min_sdk_version: "29",
+    },
 }
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7f960ab..a6bcd10 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -39,6 +39,7 @@
     shared_libs: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
+        "libSurfaceFlingerProp",
         "libbase",
         "liblog",
         "libEGL",
@@ -53,6 +54,8 @@
         "libutils",
         "libnativewindow"
     ],
+
+    header_libs: ["libsurfaceflinger_headers"],
 }
 
 // Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index dbd4ef9..6746b0a 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -240,6 +240,19 @@
     float const luma_gray = 0.50;
 };
 
+TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    // Passing in composer service as the layer handle should not crash, we'll
+    // treat it as a layer that no longer exists and silently allow sampling to
+    // occur.
+    status_t status = composer->addRegionSamplingListener(sampleArea,
+                                                          IInterface::asBinder(composer), listener);
+    ASSERT_EQ(NO_ERROR, status);
+    composer->removeRegionSamplingListener(listener);
+}
+
 TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
     fill_render(rgba_green);
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2035689..3b80945 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -18,17 +18,17 @@
 
 #include <gtest/gtest.h>
 
+#include <SurfaceFlingerProperties.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <binder/ProcessState.h>
 #include <configstore/Utils.h>
-#include <cutils/properties.h>
-#include <inttypes.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
+#include <inttypes.h>
 #include <private/gui/ComposerService.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
@@ -46,11 +46,9 @@
 
 using Transaction = SurfaceComposerClient::Transaction;
 
-static bool hasWideColorDisplay =
-        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+static bool hasWideColorDisplay = android::sysprop::has_wide_color_display(false);
 
-static bool hasHdrDisplay =
-        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+static bool hasHdrDisplay = android::sysprop::has_HDR_display(false);
 
 class FakeSurfaceComposer;
 class FakeProducerFrameEventHistory;
@@ -836,14 +834,19 @@
         return NO_ERROR;
     }
     status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
-                                          int32_t /*defaultConfig*/, float /*minRefreshRate*/,
-                                          float /*maxRefreshRate*/) {
+                                          int32_t /*defaultConfig*/,
+                                          float /*primaryRefreshRateMin*/,
+                                          float /*primaryRefreshRateMax*/,
+                                          float /*appRequestRefreshRateMin*/,
+                                          float /*appRequestRefreshRateMax*/) {
         return NO_ERROR;
     }
     status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
                                           int32_t* /*outDefaultConfig*/,
-                                          float* /*outMinRefreshRate*/,
-                                          float* /*outMaxRefreshRate*/) override {
+                                          float* /*outPrimaryRefreshRateMin*/,
+                                          float* /*outPrimaryRefreshRateMax*/,
+                                          float* /*outAppRequestRefreshRateMin*/,
+                                          float* /*outAppRequestRefreshRateMax*/) override {
         return NO_ERROR;
     };
     status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 8efaf3d..7037680 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -34,6 +34,9 @@
 
     clang: true,
 
+    header_libs: ["jni_headers"],
+    export_header_lib_headers: ["jni_headers"],
+
     shared_libs: [
         "libbase",
         "liblog",
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index ef7cc7d..11af23e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -468,7 +468,7 @@
     msg.body.key.deviceId = deviceId;
     msg.body.key.source = source;
     msg.body.key.displayId = displayId;
-    msg.body.key.hmac = hmac;
+    msg.body.key.hmac = std::move(hmac);
     msg.body.key.action = action;
     msg.body.key.flags = flags;
     msg.body.key.keyCode = keyCode;
@@ -526,7 +526,7 @@
     msg.body.motion.deviceId = deviceId;
     msg.body.motion.source = source;
     msg.body.motion.displayId = displayId;
-    msg.body.motion.hmac = hmac;
+    msg.body.motion.hmac = std::move(hmac);
     msg.body.motion.action = action;
     msg.body.motion.actionButton = actionButton;
     msg.body.motion.flags = flags;
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 998cef6..d7f8ae5 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -156,17 +156,16 @@
 }
 
 bool InputWindowInfo::isTrustedOverlay() const {
-    return layoutParamsType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
-            || layoutParamsType == TYPE_INPUT_METHOD
-            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
-            || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
-            || layoutParamsType == TYPE_STATUS_BAR
-            || layoutParamsType == TYPE_NAVIGATION_BAR
-            || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
-            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
-            || layoutParamsType == TYPE_DOCK_DIVIDER
-            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
-            || layoutParamsType == TYPE_INPUT_CONSUMER;
+    return layoutParamsType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY ||
+            layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG ||
+            layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR ||
+            layoutParamsType == TYPE_NOTIFICATION_SHADE ||
+            layoutParamsType == TYPE_NAVIGATION_BAR ||
+            layoutParamsType == TYPE_NAVIGATION_BAR_PANEL ||
+            layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY ||
+            layoutParamsType == TYPE_DOCK_DIVIDER ||
+            layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY ||
+            layoutParamsType == TYPE_INPUT_CONSUMER;
 }
 
 bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 7375a2b..9e7e4a2 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -25,5 +25,6 @@
         windows: {
             enabled: true,
         },
-    }
+    },
+    min_sdk_version: "29",
 }
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 55400c7..ee006aa 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -25,6 +25,7 @@
     name: "libnativewindow_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    min_sdk_version: "29",
 }
 
 ndk_library {
@@ -59,7 +60,6 @@
     ],
 
     shared_libs: [
-        "libhardware",
         "libcutils",
         "liblog",
         "libutils",
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index df711d2..d102696 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -147,52 +147,6 @@
     return NAME_NOT_FOUND;
 }
 
-class EGLAttributeVector {
-    struct Attribute;
-    class Adder;
-    friend class Adder;
-    KeyedVector<Attribute, EGLint> mList;
-    struct Attribute {
-        Attribute() : v(0){};
-        explicit Attribute(EGLint v) : v(v) {}
-        EGLint v;
-        bool operator<(const Attribute& other) const {
-            // this places EGL_NONE at the end
-            EGLint lhs(v);
-            EGLint rhs(other.v);
-            if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
-            if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
-            return lhs < rhs;
-        }
-    };
-    class Adder {
-        friend class EGLAttributeVector;
-        EGLAttributeVector& v;
-        EGLint attribute;
-        Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
-
-    public:
-        void operator=(EGLint value) {
-            if (attribute != EGL_NONE) {
-                v.mList.add(Attribute(attribute), value);
-            }
-        }
-        operator EGLint() const { return v.mList[attribute]; }
-    };
-
-public:
-    EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
-    void remove(EGLint attribute) {
-        if (attribute != EGL_NONE) {
-            mList.removeItem(Attribute(attribute));
-        }
-    }
-    Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
-    EGLint operator[](EGLint attribute) const { return mList[attribute]; }
-    // cast-operator to (EGLint const*)
-    operator EGLint const*() const { return &mList.keyAt(0).v; }
-};
-
 static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
                                 EGLConfig* config) {
     // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
@@ -201,16 +155,33 @@
     EGLint wantedAttribute;
     EGLint wantedAttributeValue;
 
-    EGLAttributeVector attribs;
+    std::vector<EGLint> attribs;
     if (renderableType) {
-        attribs[EGL_RENDERABLE_TYPE] = renderableType;
-        attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
-        attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
-        attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
-        attribs[EGL_RED_SIZE] = 8;
-        attribs[EGL_GREEN_SIZE] = 8;
-        attribs[EGL_BLUE_SIZE] = 8;
-        attribs[EGL_ALPHA_SIZE] = 8;
+        const ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(format);
+        const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102;
+
+        // Default to 8 bits per channel.
+        const EGLint tmpAttribs[] = {
+                EGL_RENDERABLE_TYPE,
+                renderableType,
+                EGL_RECORDABLE_ANDROID,
+                EGL_TRUE,
+                EGL_SURFACE_TYPE,
+                EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+                EGL_FRAMEBUFFER_TARGET_ANDROID,
+                EGL_TRUE,
+                EGL_RED_SIZE,
+                is1010102 ? 10 : 8,
+                EGL_GREEN_SIZE,
+                is1010102 ? 10 : 8,
+                EGL_BLUE_SIZE,
+                is1010102 ? 10 : 8,
+                EGL_ALPHA_SIZE,
+                is1010102 ? 2 : 8,
+                EGL_NONE,
+        };
+        std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)),
+                  std::back_inserter(attribs));
         wantedAttribute = EGL_NONE;
         wantedAttributeValue = EGL_NONE;
     } else {
@@ -219,7 +190,8 @@
         wantedAttributeValue = format;
     }
 
-    err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
+    err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue,
+                                   config);
     if (err == NO_ERROR) {
         EGLint caveat;
         if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
@@ -236,9 +208,20 @@
         LOG_ALWAYS_FATAL("failed to initialize EGL");
     }
 
+    const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION);
+    if (!eglVersion) {
+        checkGlError(__FUNCTION__, __LINE__);
+        LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed");
+    }
+
+    const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS);
+    if (!eglExtensions) {
+        checkGlError(__FUNCTION__, __LINE__);
+        LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed");
+    }
+
     GLExtensions& extensions = GLExtensions::getInstance();
-    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
-                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+    extensions.initWithEGLStrings(eglVersion, eglExtensions);
 
     // The code assumes that ES2 or later is available if this extension is
     // supported.
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index 724877b..19f18c0 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -68,6 +68,8 @@
 status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) {
     ATRACE_NAME("BlurFilter::setAsDrawTarget");
     mRadius = radius;
+    mDisplayX = display.physicalDisplay.left;
+    mDisplayY = display.physicalDisplay.top;
 
     if (mDisplayWidth < display.physicalDisplay.width() ||
         mDisplayHeight < display.physicalDisplay.height()) {
@@ -182,8 +184,8 @@
     if (mix >= 1 || multiPass) {
         mLastDrawTarget->bindAsReadBuffer();
         glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(),
-                          mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight,
-                          GL_COLOR_BUFFER_BIT, GL_LINEAR);
+                          mLastDrawTarget->getBufferHeight(), mDisplayX, mDisplayY, mDisplayWidth,
+                          mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
         return NO_ERROR;
     }
 
@@ -261,15 +263,6 @@
     return shader;
 }
 
-void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const {
-    ATRACE_NAME("BlurFilter::blit");
-    read.bindAsReadBuffer();
-    draw.bindAsDrawBuffer();
-    glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0,
-                      draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT,
-                      GL_LINEAR);
-}
-
 } // namespace gl
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
index 7e0819f..593a8fd 100644
--- a/libs/renderengine/gl/filters/BlurFilter.h
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -56,7 +56,6 @@
 private:
     uint32_t mRadius;
     void drawMesh(GLuint uv, GLuint position);
-    void blit(GLFramebuffer& read, GLFramebuffer& draw) const;
     string getVertexShader() const;
     string getFragmentShader() const;
     string getMixFragShader() const;
@@ -69,6 +68,8 @@
     GLFramebuffer mPongFbo;
     uint32_t mDisplayWidth = 0;
     uint32_t mDisplayHeight = 0;
+    uint32_t mDisplayX = 0;
+    uint32_t mDisplayY = 0;
     // Buffer holding the final blur pass.
     GLFramebuffer* mLastDrawTarget;
 
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index b68604d..bb78895 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -199,6 +199,7 @@
         "libhardware_headers",
         "libui_headers",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library_headers {
@@ -217,6 +218,7 @@
     export_header_lib_headers: [
         "libnativewindow_headers",
     ],
+    min_sdk_version: "29",
 }
 
 // defaults to enable VALIDATE_REGIONS traces
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
index efd61b6..7bced9b 100644
--- a/libs/ui/DeviceProductInfo.cpp
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -18,33 +18,38 @@
 
 #include <ui/FlattenableHelpers.h>
 
+#define RETURN_IF_ERROR(op) \
+    if (const status_t status = (op); status != OK) return status;
+
 namespace android {
 
 size_t DeviceProductInfo::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(name) + sizeof(manufacturerPnpId) +
-            FlattenableHelpers::getFlattenedSize(productId) + sizeof(manufactureOrModelDate);
+    return FlattenableHelpers::getFlattenedSize(name) +
+            FlattenableHelpers::getFlattenedSize(manufacturerPnpId) +
+            FlattenableHelpers::getFlattenedSize(productId) +
+            FlattenableHelpers::getFlattenedSize(manufactureOrModelDate) +
+            FlattenableHelpers::getFlattenedSize(relativeAddress);
 }
 
 status_t DeviceProductInfo::flatten(void* buffer, size_t size) const {
     if (size < getFlattenedSize()) {
         return NO_MEMORY;
     }
-    FlattenableHelpers::write(buffer, size, name);
-    FlattenableUtils::write(buffer, size, manufacturerPnpId);
-    FlattenableHelpers::write(buffer, size, productId);
-    FlattenableUtils::write(buffer, size, manufactureOrModelDate);
-    return NO_ERROR;
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, name));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufacturerPnpId));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, productId));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufactureOrModelDate));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, relativeAddress));
+    return OK;
 }
 
 status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    FlattenableHelpers::read(buffer, size, &name);
-    FlattenableUtils::read(buffer, size, manufacturerPnpId);
-    FlattenableHelpers::read(buffer, size, &productId);
-    FlattenableUtils::read(buffer, size, manufactureOrModelDate);
-    return NO_ERROR;
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &name));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufacturerPnpId));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &productId));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufactureOrModelDate));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &relativeAddress));
+    return OK;
 }
 
 } // namespace android
diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/DisplayInfo.cpp
index 6ed7e19..73a78af 100644
--- a/libs/ui/DisplayInfo.cpp
+++ b/libs/ui/DisplayInfo.cpp
@@ -20,10 +20,15 @@
 
 #include <ui/FlattenableHelpers.h>
 
+#define RETURN_IF_ERROR(op) \
+    if (const status_t status = (op); status != OK) return status;
+
 namespace android {
 
 size_t DisplayInfo::getFlattenedSize() const {
-    return sizeof(connectionType) + sizeof(density) + sizeof(secure) +
+    return FlattenableHelpers::getFlattenedSize(connectionType) +
+            FlattenableHelpers::getFlattenedSize(density) +
+            FlattenableHelpers::getFlattenedSize(secure) +
             FlattenableHelpers::getFlattenedSize(deviceProductInfo);
 }
 
@@ -31,24 +36,19 @@
     if (size < getFlattenedSize()) {
         return NO_MEMORY;
     }
-    FlattenableUtils::write(buffer, size, connectionType);
-    FlattenableUtils::write(buffer, size, density);
-    FlattenableUtils::write(buffer, size, secure);
-    FlattenableHelpers::write(buffer, size, deviceProductInfo);
-
-    return NO_ERROR;
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo));
+    return OK;
 }
 
 status_t DisplayInfo::unflatten(void const* buffer, size_t size) {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    FlattenableUtils::read(buffer, size, connectionType);
-    FlattenableUtils::read(buffer, size, density);
-    FlattenableUtils::read(buffer, size, secure);
-    FlattenableHelpers::read(buffer, size, &deviceProductInfo);
-
-    return NO_ERROR;
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo));
+    return OK;
 }
 
 } // namespace android
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index bf487c4..82ce757 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -67,19 +67,20 @@
 // ----------------------------------------------------------------------------
 
 Region::Region() {
-    mStorage.add(Rect(0,0));
+    mStorage.push_back(Rect(0, 0));
 }
 
 Region::Region(const Region& rhs)
-    : mStorage(rhs.mStorage)
 {
+    mStorage.clear();
+    mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
 #if defined(VALIDATE_REGIONS)
     validate(rhs, "rhs copy-ctor");
 #endif
 }
 
 Region::Region(const Rect& rhs) {
-    mStorage.add(rhs);
+    mStorage.push_back(rhs);
 }
 
 Region::~Region()
@@ -100,8 +101,8 @@
  * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
  * above it, and subdivided to resolve any remaining T-junctions.
  */
-static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
-        Vector<Rect>& dst, int spanDirection) {
+static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
+                                           int spanDirection) {
     dst.clear();
 
     const Rect* current = end - 1;
@@ -109,7 +110,7 @@
 
     // add first span immediately
     do {
-        dst.add(*current);
+        dst.push_back(*current);
         current--;
     } while (current->top == lastTop && current >= begin);
 
@@ -147,12 +148,12 @@
                 if (prev.right <= left) break;
 
                 if (prev.right > left && prev.right < right) {
-                    dst.add(Rect(prev.right, top, right, bottom));
+                    dst.push_back(Rect(prev.right, top, right, bottom));
                     right = prev.right;
                 }
 
                 if (prev.left > left && prev.left < right) {
-                    dst.add(Rect(prev.left, top, right, bottom));
+                    dst.push_back(Rect(prev.left, top, right, bottom));
                     right = prev.left;
                 }
 
@@ -166,12 +167,12 @@
                 if (prev.left >= right) break;
 
                 if (prev.left > left && prev.left < right) {
-                    dst.add(Rect(left, top, prev.left, bottom));
+                    dst.push_back(Rect(left, top, prev.left, bottom));
                     left = prev.left;
                 }
 
                 if (prev.right > left && prev.right < right) {
-                    dst.add(Rect(left, top, prev.right, bottom));
+                    dst.push_back(Rect(left, top, prev.right, bottom));
                     left = prev.right;
                 }
                 // if an entry in the previous span is too far left, nothing further right in the
@@ -183,7 +184,7 @@
         }
 
         if (left < right) {
-            dst.add(Rect(left, top, right, bottom));
+            dst.push_back(Rect(left, top, right, bottom));
         }
 
         current--;
@@ -201,13 +202,14 @@
     if (r.isEmpty()) return r;
     if (r.isRect()) return r;
 
-    Vector<Rect> reversed;
+    FatVector<Rect> reversed;
     reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
 
     Region outputRegion;
-    reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
-            outputRegion.mStorage, direction_LTR);
-    outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
+    reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
+                                   outputRegion.mStorage, direction_LTR);
+    outputRegion.mStorage.push_back(
+            r.getBounds()); // to make region valid, mStorage must end with bounds
 
 #if defined(VALIDATE_REGIONS)
     validate(outputRegion, "T-Junction free region");
@@ -222,7 +224,8 @@
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
-    mStorage = rhs.mStorage;
+    mStorage.clear();
+    mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
     return *this;
 }
 
@@ -231,7 +234,7 @@
     if (mStorage.size() >= 2) {
         const Rect bounds(getBounds());
         mStorage.clear();
-        mStorage.add(bounds);
+        mStorage.push_back(bounds);
     }
     return *this;
 }
@@ -255,25 +258,25 @@
 void Region::clear()
 {
     mStorage.clear();
-    mStorage.add(Rect(0,0));
+    mStorage.push_back(Rect(0, 0));
 }
 
 void Region::set(const Rect& r)
 {
     mStorage.clear();
-    mStorage.add(r);
+    mStorage.push_back(r);
 }
 
 void Region::set(int32_t w, int32_t h)
 {
     mStorage.clear();
-    mStorage.add(Rect(w, h));
+    mStorage.push_back(Rect(w, h));
 }
 
 void Region::set(uint32_t w, uint32_t h)
 {
     mStorage.clear();
-    mStorage.add(Rect(w, h));
+    mStorage.push_back(Rect(w, h));
 }
 
 bool Region::isTriviallyEqual(const Region& region) const {
@@ -299,13 +302,16 @@
 void Region::addRectUnchecked(int l, int t, int r, int b)
 {
     Rect rect(l,t,r,b);
-    size_t where = mStorage.size() - 1;
-    mStorage.insertAt(rect, where, 1);
+    mStorage.insert(mStorage.end() - 1, rect);
 }
 
 // ----------------------------------------------------------------------------
 
 Region& Region::orSelf(const Rect& r) {
+    if (isEmpty()) {
+        set(r);
+        return *this;
+    }
     return operationSelf(r, op_or);
 }
 Region& Region::xorSelf(const Rect& r) {
@@ -326,6 +332,10 @@
 // ----------------------------------------------------------------------------
 
 Region& Region::orSelf(const Region& rhs) {
+    if (isEmpty()) {
+        *this = rhs;
+        return *this;
+    }
     return operationSelf(rhs, op_or);
 }
 Region& Region::xorSelf(const Region& rhs) {
@@ -350,7 +360,7 @@
 
 Region& Region::scaleSelf(float sx, float sy) {
     size_t count = mStorage.size();
-    Rect* rects = mStorage.editArray();
+    Rect* rects = mStorage.data();
     while (count) {
         rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
         rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
@@ -455,10 +465,10 @@
 class Region::rasterizer : public region_operator<Rect>::region_rasterizer
 {
     Rect bounds;
-    Vector<Rect>& storage;
+    FatVector<Rect>& storage;
     Rect* head;
     Rect* tail;
-    Vector<Rect> span;
+    FatVector<Rect> span;
     Rect* cur;
 public:
     explicit rasterizer(Region& reg)
@@ -485,8 +495,8 @@
         flushSpan();
     }
     if (storage.size()) {
-        bounds.top = storage.itemAt(0).top;
-        bounds.bottom = storage.top().bottom;
+        bounds.top = storage.front().top;
+        bounds.bottom = storage.back().bottom;
         if (storage.size() == 1) {
             storage.clear();
         }
@@ -494,7 +504,7 @@
         bounds.left  = 0;
         bounds.right = 0;
     }
-    storage.add(bounds);
+    storage.push_back(bounds);
 }
 
 void Region::rasterizer::operator()(const Rect& rect)
@@ -509,15 +519,15 @@
             return;
         }
     }
-    span.add(rect);
-    cur = span.editArray() + (span.size() - 1);
+    span.push_back(rect);
+    cur = span.data() + (span.size() - 1);
 }
 
 void Region::rasterizer::flushSpan()
 {
     bool merge = false;
     if (tail-head == ssize_t(span.size())) {
-        Rect const* p = span.editArray();
+        Rect const* p = span.data();
         Rect const* q = head;
         if (p->top == q->bottom) {
             merge = true;
@@ -532,17 +542,17 @@
         }
     }
     if (merge) {
-        const int bottom = span[0].bottom;
+        const int bottom = span.front().bottom;
         Rect* r = head;
         while (r != tail) {
             r->bottom = bottom;
             r++;
         }
     } else {
-        bounds.left = min(span.itemAt(0).left, bounds.left);
-        bounds.right = max(span.top().right, bounds.right);
-        storage.appendVector(span);
-        tail = storage.editArray() + storage.size();
+        bounds.left = min(span.front().left, bounds.left);
+        bounds.right = max(span.back().right, bounds.right);
+        storage.insert(storage.end(), span.begin(), span.end());
+        tail = storage.data() + storage.size();
         head = tail - span.size();
     }
     span.clear();
@@ -550,7 +560,7 @@
 
 bool Region::validate(const Region& reg, const char* name, bool silent)
 {
-    if (reg.mStorage.isEmpty()) {
+    if (reg.mStorage.empty()) {
         ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
         // return immediately as the code below assumes mStorage is non-empty
         return false;
@@ -689,9 +699,8 @@
     }
     sk_dst.op(sk_lhs, sk_rhs, sk_op);
 
-    if (sk_dst.isEmpty() && dst.isEmpty())
-        return;
-    
+    if (sk_dst.empty() && dst.empty()) return;
+
     bool same = true;
     Region::const_iterator head = dst.begin();
     Region::const_iterator const tail = dst.end();
@@ -786,7 +795,7 @@
         validate(reg, "translate (before)");
 #endif
         size_t count = reg.mStorage.size();
-        Rect* rects = reg.mStorage.editArray();
+        Rect* rects = reg.mStorage.data();
         while (count) {
             rects->offsetBy(dx, dy);
             rects++;
@@ -866,24 +875,25 @@
         ALOGE("Region::unflatten() failed, invalid region");
         return BAD_VALUE;
     }
-    mStorage = result.mStorage;
+    mStorage.clear();
+    mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
     return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
 
 Region::const_iterator Region::begin() const {
-    return mStorage.array();
+    return mStorage.data();
 }
 
 Region::const_iterator Region::end() const {
     // Workaround for b/77643177
     // mStorage should never be empty, but somehow it is and it's causing
     // an abort in ubsan
-    if (mStorage.isEmpty()) return mStorage.array();
+    if (mStorage.empty()) return mStorage.data();
 
     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
-    return mStorage.array() + numRects;
+    return mStorage.data() + numRects;
 }
 
 Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h
index cc5ebe4..0bc1e5c 100644
--- a/libs/ui/include/ui/DeviceProductInfo.h
+++ b/libs/ui/include/ui/DeviceProductInfo.h
@@ -22,6 +22,7 @@
 #include <string>
 #include <type_traits>
 #include <variant>
+#include <vector>
 
 #include <utils/Flattenable.h>
 
@@ -58,6 +59,11 @@
     static_assert(std::is_trivially_copyable_v<ManufactureOrModelDate>);
     ManufactureOrModelDate manufactureOrModelDate;
 
+    // Relative address in the display network. Empty vector indicates that the
+    // address is unavailable.
+    // For example, for HDMI connected device this will be the physical address.
+    std::vector<uint8_t> relativeAddress;
+
     bool isFixedSize() const { return false; }
     size_t getFlattenedSize() const;
     status_t flatten(void* buffer, size_t size) const;
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
new file mode 100644
index 0000000..25fe3a0
--- /dev/null
+++ b/libs/ui/include/ui/FatVector.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_REGION_FAT_VECTOR_H
+#define ANDROID_REGION_FAT_VECTOR_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+#include <vector>
+
+namespace android {
+
+template <typename T, size_t SIZE = 4>
+class InlineStdAllocator {
+public:
+    struct Allocation {
+    private:
+        Allocation(const Allocation&) = delete;
+        void operator=(const Allocation&) = delete;
+
+    public:
+        Allocation() {}
+        // char array instead of T array, so memory is uninitialized, with no destructors run
+        char array[sizeof(T) * SIZE];
+        bool inUse = false;
+    };
+
+    typedef T value_type; // needed to implement std::allocator
+    typedef T* pointer;   // needed to implement std::allocator
+
+    explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+    InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
+    ~InlineStdAllocator() {}
+
+    T* allocate(size_t num, const void* = 0) {
+        if (!mAllocation.inUse && num <= SIZE) {
+            mAllocation.inUse = true;
+            return static_cast<T*>(static_cast<void*>(mAllocation.array));
+        } else {
+            return static_cast<T*>(static_cast<void*>(malloc(num * sizeof(T))));
+        }
+    }
+
+    void deallocate(pointer p, size_t) {
+        if (p == static_cast<T*>(static_cast<void*>(mAllocation.array))) {
+            mAllocation.inUse = false;
+        } else {
+            // 'free' instead of delete here - destruction handled separately
+            free(p);
+        }
+    }
+    Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE = 4>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+    FatVector()
+          : std::vector<T, InlineStdAllocator<T, SIZE>>(InlineStdAllocator<T, SIZE>(mAllocation)) {
+        this->reserve(SIZE);
+    }
+
+    explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
+
+private:
+    typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+} // namespace android
+
+#endif // ANDROID_REGION_FAT_VECTOR_H
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 2db3b10..6bb7b8d 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -21,13 +21,13 @@
 #include <sys/types.h>
 #include <ostream>
 
-#include <utils/Vector.h>
-
 #include <ui/Rect.h>
 #include <utils/Flattenable.h>
 
 #include <android-base/macros.h>
 
+#include "FatVector.h"
+
 #include <string>
 
 namespace android {
@@ -180,7 +180,7 @@
     // with an extra Rect as the last element which is set to the
     // bounds of the region. However, if the region is
     // a simple Rect then mStorage contains only that rect.
-    Vector<Rect> mStorage;
+    FatVector<Rect> mStorage;
 };
 
 
@@ -235,4 +235,3 @@
 }; // namespace android
 
 #endif // ANDROID_UI_REGION_H
-
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h
index bdf4804..8e316d8 100644
--- a/libs/ui/include_private/ui/FlattenableHelpers.h
+++ b/libs/ui/include_private/ui/FlattenableHelpers.h
@@ -16,56 +16,145 @@
 
 #pragma once
 
+#include <numeric>
 #include <optional>
 #include <type_traits>
+#include <vector>
 
 #include <utils/Flattenable.h>
 
+#define RETURN_IF_ERROR(op) \
+    if (const status_t status = (op); status != OK) return status;
+
 namespace android {
 
 struct FlattenableHelpers {
-    // Flattenable helpers for reading and writing std::string
-    static size_t getFlattenedSize(const std::string& str) { return str.length() + 1; }
-
-    static void write(void*& buffer, size_t& size, const std::string& str) {
-        strcpy(reinterpret_cast<char*>(buffer), str.c_str());
-        FlattenableUtils::advance(buffer, size, getFlattenedSize(str));
+    // Helpers for reading and writing POD structures
+    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+    static constexpr size_t getFlattenedSize(const T&) {
+        return sizeof(T);
     }
 
-    static void read(void const*& buffer, size_t& size, std::string* str) {
-        str->assign(reinterpret_cast<const char*>(buffer));
-        FlattenableUtils::advance(buffer, size, getFlattenedSize(*str));
+    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+    static status_t flatten(void** buffer, size_t* size, const T& value) {
+        if (*size < sizeof(T)) return NO_MEMORY;
+        FlattenableUtils::write(*buffer, *size, value);
+        return OK;
     }
 
-    // Flattenable utils for reading and writing std::optional
-    template <class T, typename = std::enable_if_t<std::is_base_of_v<LightFlattenable<T>, T>>>
+    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+    static status_t unflatten(const void** buffer, size_t* size, T* value) {
+        if (*size < sizeof(T)) return NO_MEMORY;
+        FlattenableUtils::read(*buffer, *size, *value);
+        return OK;
+    }
+
+    // Helpers for reading and writing std::string
+    static size_t getFlattenedSize(const std::string& str) {
+        return sizeof(uint64_t) + str.length();
+    }
+
+    static status_t flatten(void** buffer, size_t* size, const std::string& str) {
+        if (*size < getFlattenedSize(str)) return NO_MEMORY;
+        flatten(buffer, size, (uint64_t)str.length());
+        memcpy(reinterpret_cast<char*>(*buffer), str.c_str(), str.length());
+        FlattenableUtils::advance(*buffer, *size, str.length());
+        return OK;
+    }
+
+    static status_t unflatten(const void** buffer, size_t* size, std::string* str) {
+        uint64_t length;
+        RETURN_IF_ERROR(unflatten(buffer, size, &length));
+        if (*size < length) return NO_MEMORY;
+        str->assign(reinterpret_cast<const char*>(*buffer), length);
+        FlattenableUtils::advance(*buffer, *size, length);
+        return OK;
+    }
+
+    // Helpers for reading and writing LightFlattenable
+    template <class T>
+    static size_t getFlattenedSize(const LightFlattenable<T>& value) {
+        return value.getFlattenedSize();
+    }
+
+    template <class T>
+    static status_t flatten(void** buffer, size_t* size, const LightFlattenable<T>& value) {
+        RETURN_IF_ERROR(value.flatten(*buffer, *size));
+        FlattenableUtils::advance(*buffer, *size, value.getFlattenedSize());
+        return OK;
+    }
+
+    template <class T>
+    static status_t unflatten(const void** buffer, size_t* size, LightFlattenable<T>* value) {
+        RETURN_IF_ERROR(value->unflatten(*buffer, *size));
+        FlattenableUtils::advance(*buffer, *size, value->getFlattenedSize());
+        return OK;
+    }
+
+    // Helpers for reading and writing std::optional
+    template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>>
     static size_t getFlattenedSize(const std::optional<T>& value) {
-        return sizeof(bool) + (value ? value->getFlattenedSize() : 0);
+        return sizeof(bool) + (value ? getFlattenedSize(*value) : 0);
     }
 
-    template <class T, typename = std::enable_if_t<std::is_base_of_v<LightFlattenable<T>, T>>>
-    static void write(void*& buffer, size_t& size, const std::optional<T>& value) {
+    template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>>
+    static status_t flatten(void** buffer, size_t* size, const std::optional<T>& value) {
         if (value) {
-            FlattenableUtils::write(buffer, size, true);
-            value->flatten(buffer, size);
-            FlattenableUtils::advance(buffer, size, value->getFlattenedSize());
+            RETURN_IF_ERROR(flatten(buffer, size, true));
+            RETURN_IF_ERROR(flatten(buffer, size, *value));
         } else {
-            FlattenableUtils::write(buffer, size, false);
+            RETURN_IF_ERROR(flatten(buffer, size, false));
         }
+        return OK;
     }
 
-    template <class T, typename = std::enable_if_t<std::is_base_of_v<LightFlattenable<T>, T>>>
-    static void read(void const*& buffer, size_t& size, std::optional<T>* value) {
+    template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>>
+    static status_t unflatten(const void** buffer, size_t* size, std::optional<T>* value) {
         bool isPresent;
-        FlattenableUtils::read(buffer, size, isPresent);
+        RETURN_IF_ERROR(unflatten(buffer, size, &isPresent));
         if (isPresent) {
             *value = T();
-            (*value)->unflatten(buffer, size);
-            FlattenableUtils::advance(buffer, size, (*value)->getFlattenedSize());
+            RETURN_IF_ERROR(unflatten(buffer, size, &(**value)));
         } else {
             value->reset();
         }
+        return OK;
+    }
+
+    // Helpers for reading and writing std::vector
+    template <class T>
+    static size_t getFlattenedSize(const std::vector<T>& value) {
+        return std::accumulate(value.begin(), value.end(), sizeof(uint64_t),
+                               [](size_t sum, const T& element) {
+                                   return sum + getFlattenedSize(element);
+                               });
+    }
+
+    template <class T>
+    static status_t flatten(void** buffer, size_t* size, const std::vector<T>& value) {
+        RETURN_IF_ERROR(flatten(buffer, size, (uint64_t)value.size()));
+        for (const auto& element : value) {
+            RETURN_IF_ERROR(flatten(buffer, size, element));
+        }
+        return OK;
+    }
+
+    template <class T>
+    static status_t unflatten(const void** buffer, size_t* size, std::vector<T>* value) {
+        uint64_t numElements;
+        RETURN_IF_ERROR(unflatten(buffer, size, &numElements));
+        // We don't need an extra size check since each iteration of the loop does that
+        std::vector<T> elements;
+        for (size_t i = 0; i < numElements; i++) {
+            T element;
+            RETURN_IF_ERROR(unflatten(buffer, size, &element));
+            elements.push_back(element);
+        }
+        *value = std::move(elements);
+        return OK;
     }
 };
 
 } // namespace android
+
+#undef RETURN_IF_ERROR
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h
new file mode 120000
index 0000000..bf30166
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FatVector.h
@@ -0,0 +1 @@
+../../include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index b53342c..28ef77a 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,6 +29,13 @@
 }
 
 cc_test {
+    name: "FlattenableHelpers_test",
+    shared_libs: ["libui"],
+    srcs: ["FlattenableHelpers_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
     name: "GraphicBufferAllocator_test",
     header_libs: [
         "libnativewindow_headers",
diff --git a/libs/ui/tests/FlattenableHelpers_test.cpp b/libs/ui/tests/FlattenableHelpers_test.cpp
new file mode 100644
index 0000000..db32bc7
--- /dev/null
+++ b/libs/ui/tests/FlattenableHelpers_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FlattenableHelpersTest"
+
+#include <ui/FlattenableHelpers.h>
+
+#include <gtest/gtest.h>
+#include <utils/Flattenable.h>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android {
+
+namespace {
+
+struct TestLightFlattenable : LightFlattenable<TestLightFlattenable> {
+    std::unique_ptr<int32_t> ptr;
+
+    bool isFixedSize() const { return true; }
+    size_t getFlattenedSize() const { return sizeof(int32_t); }
+
+    status_t flatten(void* buffer, size_t size) const {
+        FlattenableUtils::write(buffer, size, *ptr);
+        return OK;
+    }
+
+    status_t unflatten(void const* buffer, size_t size) {
+        int value;
+        FlattenableUtils::read(buffer, size, value);
+        ptr = std::make_unique<int32_t>(value);
+        return OK;
+    }
+};
+
+class FlattenableHelpersTest : public testing::Test {
+public:
+    template <class T>
+    void testWriteThenRead(const T& value, size_t bufferSize) {
+        std::vector<int8_t> buffer(bufferSize);
+        auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+        size_t size = buffer.size();
+        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+
+        auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+        size = buffer.size();
+        T valueRead;
+        ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
+        EXPECT_EQ(value, valueRead);
+    }
+
+    template <class T>
+    void testTriviallyCopyable(const T& value) {
+        testWriteThenRead(value, sizeof(T));
+    }
+
+    template <class T>
+    void testWriteThenRead(const T& value) {
+        testWriteThenRead(value, FlattenableHelpers::getFlattenedSize(value));
+    }
+};
+
+TEST_F(FlattenableHelpersTest, TriviallyCopyable) {
+    testTriviallyCopyable(42);
+    testTriviallyCopyable(1LL << 63);
+    testTriviallyCopyable(false);
+    testTriviallyCopyable(true);
+    testTriviallyCopyable(std::optional<int>());
+    testTriviallyCopyable(std::optional<int>(4));
+}
+
+TEST_F(FlattenableHelpersTest, String) {
+    testWriteThenRead(std::string("Android"));
+    testWriteThenRead(std::string());
+}
+
+TEST_F(FlattenableHelpersTest, Vector) {
+    testWriteThenRead(std::vector<int>({1, 2, 3}));
+    testWriteThenRead(std::vector<int>());
+}
+
+TEST_F(FlattenableHelpersTest, OptionalOfLightFlattenable) {
+    std::vector<size_t> buffer;
+    constexpr int kInternalValue = 16;
+    {
+        std::optional<TestLightFlattenable> value =
+                TestLightFlattenable{.ptr = std::make_unique<int32_t>(kInternalValue)};
+        buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0);
+        void* rawBuffer = reinterpret_cast<void*>(buffer.data());
+        size_t size = buffer.size();
+        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+    }
+
+    const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+    size_t size = buffer.size();
+    std::optional<TestLightFlattenable> valueRead;
+    ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
+    ASSERT_TRUE(valueRead.has_value());
+    EXPECT_EQ(kInternalValue, *valueRead->ptr);
+}
+
+TEST_F(FlattenableHelpersTest, NullOptionalOfLightFlattenable) {
+    std::vector<size_t> buffer;
+    {
+        std::optional<TestLightFlattenable> value;
+        buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0);
+        void* rawBuffer = reinterpret_cast<void*>(buffer.data());
+        size_t size = buffer.size();
+        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+    }
+
+    const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+    size_t size = buffer.size();
+    std::optional<TestLightFlattenable> valueRead;
+    ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
+    ASSERT_FALSE(valueRead.has_value());
+}
+
+} // namespace
+} // namespace android
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 23a4224..24ba830 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -2,6 +2,7 @@
     name: "libpdx_headers",
     export_include_dirs: ["private"],
     vendor_available: true,
+    min_sdk_version: "29",
 }
 
 cc_library_static {
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index 410e234..7fafd3b 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -11,6 +11,7 @@
     "libutils",
     "libnativewindow",
     "libpdx_default_transport",
+    "libSurfaceFlingerProp",
 ]
 
 static_libs = [
@@ -32,5 +33,6 @@
         "-Wall",
         "-Werror",
     ],
+    header_libs: ["libsurfaceflinger_headers"],
     name: "vrflinger_test",
 }
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index 7075e88..efd6d1d 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -1,3 +1,4 @@
+#include <SurfaceFlingerProperties.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/types.h>
 #include <android/hardware_buffer.h>
@@ -147,9 +148,7 @@
   // Exit immediately if the device doesn't support vr flinger. This ConfigStore
   // check is the same mechanism used by surface flinger to decide if it should
   // initialize vr flinger.
-  bool vr_flinger_enabled =
-      getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>(
-          false);
+  bool vr_flinger_enabled = android::sysprop::use_vr_flinger(false);
   if (!vr_flinger_enabled) {
     return;
   }
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index e255b9d..3997134 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -75,7 +75,6 @@
         "bionic_libc_platform_headers",
         "gl_headers",
         "libsystem_headers",
-        "libhardware_headers",
         "libnativebase_headers",
     ],
     export_header_lib_headers: ["gl_headers"],
@@ -154,6 +153,7 @@
         "libnativebridge_lazy",
         "libnativeloader_lazy",
         "libutils",
+        "libSurfaceFlingerProp",
     ],
     static_libs: [
         "libEGL_getProcAddress",
@@ -165,6 +165,7 @@
         symbol_file: "libEGL.map.txt",
         versions: ["29"],
     },
+    header_libs: ["libsurfaceflinger_headers"],
 }
 
 cc_test {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index e19802b..391a410 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -222,13 +222,6 @@
         return cnx->dso;
     }
 
-    // Check if we should use ANGLE early, so loading each driver doesn't require repeated queries.
-    if (android::GraphicsEnv::getInstance().shouldUseAngle()) {
-        cnx->shouldUseAngle = true;
-    } else {
-        cnx->shouldUseAngle = false;
-    }
-
     // Firstly, try to load ANGLE driver.
     driver_t* hnd = attempt_to_load_angle(cnx);
     if (!hnd) {
@@ -278,6 +271,12 @@
     if (!hnd) {
         android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
                                                             false, systemTime() - openTime);
+    } else {
+        // init_angle_backend will check if loaded driver is ANGLE or not,
+        // will set cnx->useAngle appropriately.
+        // Do this here so that we use ANGLE path when driver is ANGLE (e.g. loaded as native),
+        // not just loading ANGLE as option.
+        init_angle_backend(hnd->dso[2], cnx);
     }
 
     LOG_ALWAYS_FATAL_IF(!hnd,
@@ -317,14 +316,7 @@
     delete hnd;
     cnx->dso = nullptr;
 
-    cnx->shouldUseAngle = false;
-    cnx->angleDecided = false;
     cnx->useAngle = false;
-
-    if (cnx->vendorEGL) {
-        dlclose(cnx->vendorEGL);
-        cnx->vendorEGL = nullptr;
-    }
 }
 
 void Loader::init_api(void* dso,
@@ -491,7 +483,7 @@
     return dso;
 }
 
-static void* load_angle_from_namespace(const char* kind, android_namespace_t* ns) {
+static void* load_angle(const char* kind, android_namespace_t* ns) {
     const android_dlextinfo dlextinfo = {
             .flags = ANDROID_DLEXT_USE_NAMESPACE,
             .library_namespace = ns,
@@ -511,69 +503,6 @@
     return nullptr;
 }
 
-static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
-    void* so = nullptr;
-
-    if ((cnx->shouldUseAngle) || android::GraphicsEnv::getInstance().shouldUseAngle()) {
-        so = load_angle_from_namespace(kind, ns);
-        cnx->shouldUseAngle = true;
-    } else {
-        cnx->shouldUseAngle = false;
-    }
-
-    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];
-
-        property_get("debug.hwui.renderer", prop, "UNSET");
-        ALOGV("Skia's renderer set to %s", prop);
-
-        EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
-        property_get("debug.angle.backend", prop, "0");
-        switch (atoi(prop)) {
-            case 1:
-                ALOGV("%s: Requesting OpenGLES back-end", __FUNCTION__);
-                angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
-                break;
-            case 2:
-                ALOGV("%s: Requesting Vulkan back-end", __FUNCTION__);
-                angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
-                break;
-            default:
-                break;
-        }
-
-        cnx->angleBackend = angleBackendDefault;
-        if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
-            // Find and load vendor libEGL for ANGLE's GL back-end to use.
-            char prop[PROPERTY_VALUE_MAX + 1];
-            for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-                if (property_get(key, prop, nullptr) <= 0) {
-                    continue;
-                }
-                void* dso = load_system_driver("EGL", prop, true);
-                if (dso) {
-                    cnx->vendorEGL = dso;
-                    break;
-                }
-            }
-            if (!cnx->vendorEGL) {
-                cnx->vendorEGL = load_system_driver("EGL", nullptr, true);
-            }
-        }
-    } else {
-        ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
-            android::GraphicsEnv::getInstance().getAngleAppName().c_str());
-        cnx->useAngle = false;
-    }
-    cnx->angleDecided = true;
-
-    return so;
-}
-
 static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
     ATRACE_CALL();
     const android_dlextinfo dlextinfo = {
@@ -597,6 +526,11 @@
 
 Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
     ATRACE_CALL();
+
+    if (!android::GraphicsEnv::getInstance().shouldUseAngle()) {
+        return nullptr;
+    }
+
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (!ns) {
         return nullptr;
@@ -606,22 +540,33 @@
     driver_t* hnd = nullptr;
 
     // ANGLE doesn't ship with GLES library, and thus we skip GLES driver.
-    void* dso = load_angle("EGL", ns, cnx);
+    void* dso = load_angle("EGL", ns);
     if (dso) {
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
-        dso = load_angle("GLESv1_CM", ns, cnx);
+        dso = load_angle("GLESv1_CM", ns);
         initialize_api(dso, cnx, GLESv1_CM);
         hnd->set(dso, GLESv1_CM);
 
-        dso = load_angle("GLESv2", ns, cnx);
+        dso = load_angle("GLESv2", ns);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
     }
     return hnd;
 }
 
+void Loader::init_angle_backend(void* dso, egl_connection_t* cnx) {
+    void* pANGLEGetDisplayPlatform = dlsym(dso, "ANGLEGetDisplayPlatform");
+    if (pANGLEGetDisplayPlatform) {
+        ALOGV("ANGLE GLES library in use");
+        cnx->useAngle = true;
+    } else {
+        ALOGV("Native GLES library in use");
+        cnx->useAngle = false;
+    }
+}
+
 Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
     ATRACE_CALL();
 #ifndef __ANDROID_VNDK__
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 6f31ab4..7b2d7c9 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -60,6 +60,7 @@
     driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact);
     void unload_system_driver(egl_connection_t* cnx);
     void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
+    void init_angle_backend(void* dso, egl_connection_t* cnx);
 
     static __attribute__((noinline))
     void init_api(void* dso,
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 0581708..d5d57d7 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -16,8 +16,6 @@
 
 #include <stdlib.h>
 
-#include <hardware/gralloc.h>
-
 #include <EGL/egl.h>
 
 #include <cutils/properties.h>
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index a58e87c..6af7cd2 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -31,6 +31,7 @@
 #include "egl_object.h"
 #include "egl_tls.h"
 
+#include <SurfaceFlingerProperties.h>
 #include <android/dlext.h>
 #include <dlfcn.h>
 #include <graphicsenv/GraphicsEnv.h>
@@ -133,45 +134,6 @@
     return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
 }
 
-static bool addAnglePlatformAttributes(egl_connection_t* const cnx,
-                                       std::vector<EGLAttrib>& attrs) {
-    intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
-
-    attrs.reserve(4 * 2);
-
-    attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
-    attrs.push_back(cnx->angleBackend);
-
-    switch (cnx->angleBackend) {
-        case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
-            ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
-            char prop[PROPERTY_VALUE_MAX];
-            property_get("debug.angle.validation", prop, "0");
-            attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
-            attrs.push_back(atoi(prop));
-            break;
-        case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
-            ALOGV("%s: Requesting Default ANGLE back-end", __FUNCTION__);
-            break;
-        case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
-            ALOGV("%s: Requesting OpenGL ES ANGLE back-end", __FUNCTION__);
-            // NOTE: This is only valid if the backend is OpenGL
-            attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE);
-            attrs.push_back(vendorEGL);
-
-            // Context virtualization is only available on GL back-end.
-            // Needed to support threading with GL back-end
-            attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
-            attrs.push_back(EGL_FALSE);
-            break;
-        default:
-            ALOGE("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
-            break;
-    }
-
-    return true;
-}
-
 static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx,
                                           const EGLAttrib* attrib_list, EGLint* error) {
     EGLDisplay dpy = EGL_NO_DISPLAY;
@@ -186,11 +148,14 @@
             }
         }
 
-        if (!addAnglePlatformAttributes(cnx, attrs)) {
-            ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
-            *error = EGL_BAD_PARAMETER;
-            return EGL_NO_DISPLAY;
-        }
+        attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+        attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
+
+        char prop[PROPERTY_VALUE_MAX];
+        property_get("debug.angle.validation", prop, "0");
+        attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
+        attrs.push_back(atoi(prop));
+
         attrs.push_back(EGL_NONE);
 
         dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
@@ -361,9 +326,7 @@
 
         // Note: CDD requires that devices supporting wide color and/or HDR color also support
         // the EGL_KHR_gl_colorspace extension.
-        bool wideColorBoardConfig =
-                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
-                        false);
+        bool wideColorBoardConfig = android::sysprop::has_wide_color_display(false);
 
         // Add wide-color extensions if device can support wide-color
         if (wideColorBoardConfig && hasColorSpaceSupport) {
@@ -373,8 +336,7 @@
                     "EGL_EXT_gl_colorspace_display_p3_passthrough ");
         }
 
-        bool hasHdrBoardConfig =
-                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+        bool hasHdrBoardConfig = android::sysprop::has_HDR_display(false);
 
         if (hasHdrBoardConfig && hasColorSpaceSupport) {
             // hasHDRBoardConfig indicates the system is capable of supporting HDR content.
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index c8840f9..c976c60 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -23,8 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <hardware/gralloc1.h>
-
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <EGL/eglext_angle.h>
@@ -721,7 +719,7 @@
 
     // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
     // native_window_* calls, so don't do them here.
-    if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+    if (!cnx->useAngle) {
         int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
         if (result < 0) {
             ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
@@ -740,14 +738,14 @@
     std::vector<AttrType> strippedAttribList;
     if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) {
         ALOGE("error invalid colorspace: %d", colorSpace);
-        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+        if (!cnx->useAngle) {
             native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
         }
         return EGL_NO_SURFACE;
     }
     attrib_list = strippedAttribList.data();
 
-    if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+    if (!cnx->useAngle) {
         int err = native_window_set_buffers_format(window, format);
         if (err != 0) {
             ALOGE("error setting native window pixel format: %s (%d)", strerror(-err), err);
@@ -779,7 +777,7 @@
     }
 
     // EGLSurface creation failed
-    if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+    if (!cnx->useAngle) {
         native_window_set_buffers_format(window, 0);
         native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
     }
@@ -1419,7 +1417,7 @@
         }
     }
 
-    if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+    if (!s->cnx->useAngle) {
         if (!sendSurfaceMetadata(s)) {
             native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
             return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
@@ -1444,7 +1442,7 @@
         androidRect.bottom = y;
         androidRects.push_back(androidRect);
     }
-    if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+    if (!s->cnx->useAngle) {
         native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(),
                                          androidRects.size());
     }
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7bb9b59..5fbffbd 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -81,11 +81,7 @@
     void*               libGles2;
 
     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;
-    void*               vendorEGL;
 };
 // clang-format on
 
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index 8bfe517..e3912a8 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -25,6 +25,7 @@
         "liblog",
         "libutils",
         "libnativewindow",
+        "libSurfaceFlingerProp",
     ],
 
     include_dirs: [
@@ -34,5 +35,6 @@
 
     header_libs: [
         "bionic_libc_platform_headers",
+        "libsurfaceflinger_headers",
     ],
 }
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index cca91c3..510226d 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 
+#include <SurfaceFlingerProperties.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 
 #include <configstore/Utils.h>
@@ -52,11 +53,9 @@
 
 #define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
 
-static bool hasWideColorDisplay =
-        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+static bool hasWideColorDisplay = android::sysprop::has_wide_color_display(false);
 
-static bool hasHdrDisplay =
-        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+static bool hasHdrDisplay = android::sysprop::has_HDR_display(false);
 
 class EGLTest : public ::testing::Test {
 public:
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
new file mode 100644
index 0000000..b875814
--- /dev/null
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -0,0 +1,22 @@
+// 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.
+
+bpf {
+    name: "gpu_mem.o",
+    srcs: ["gpu_mem.c"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
new file mode 100644
index 0000000..c75213b
--- /dev/null
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include <bpf_helpers.h>
+
+/*
+ * On Android the number of active processes using gpu is limited.
+ * So this is assumed to be true: SUM(num_procs_using_gpu[i]) <= 1024
+ */
+#define GPU_MEM_TOTAL_MAP_SIZE 1024
+
+/*
+ * This map maintains the global and per process gpu memory total counters.
+ *
+ * The KEY is ((gpu_id << 32) | pid) while VAL is the size in bytes.
+ * Use HASH type here since key is not int.
+ * Pass AID_GRAPHICS as gid since gpuservice is in the graphics group.
+ */
+DEFINE_BPF_MAP_GRO(gpu_mem_total_map, HASH, uint64_t, uint64_t, GPU_MEM_TOTAL_MAP_SIZE,
+                   AID_GRAPHICS);
+
+/* This struct aligns with the fields offsets of the raw tracepoint format */
+struct gpu_mem_total_args {
+    uint64_t ignore;
+    /* Actual fields start at offset 8 */
+    uint32_t gpu_id;
+    uint32_t pid;
+    uint64_t size;
+};
+
+/*
+ * This program parses the gpu_mem/gpu_mem_total tracepoint's data into
+ * {KEY, VAL} pair used to update the corresponding bpf map.
+ *
+ * Pass AID_GRAPHICS as gid since gpuservice is in the graphics group.
+ * Upon seeing size 0, the corresponding KEY needs to be cleaned up.
+ */
+DEFINE_BPF_PROG("tracepoint/gpu_mem/gpu_mem_total", AID_ROOT, AID_GRAPHICS, tp_gpu_mem_total)
+(struct gpu_mem_total_args* args) {
+    uint64_t key = 0;
+    uint64_t cur_val = 0;
+    uint64_t* prev_val = NULL;
+
+    /* The upper 32 bits are for gpu_id while the lower is the pid */
+    key = ((uint64_t)args->gpu_id << 32) | args->pid;
+    cur_val = args->size;
+
+    if (!cur_val) {
+        bpf_gpu_mem_total_map_delete_elem(&key);
+        return 0;
+    }
+
+    prev_val = bpf_gpu_mem_total_map_lookup_elem(&key);
+    if (prev_val) {
+        *prev_val = cur_val;
+    } else {
+        bpf_gpu_mem_total_map_update_elem(&key, &cur_val, BPF_NOEXIST);
+    }
+    return 0;
+}
+
+char _license[] SEC("license") = "Apache 2.0";
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
new file mode 100644
index 0000000..b2230b6
--- /dev/null
+++ b/services/gpuservice/gpumem/Android.bp
@@ -0,0 +1,41 @@
+// 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.
+
+cc_library_shared {
+    name: "libgpumem",
+    srcs: [
+        "GpuMem.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbpf",
+        "libbpf_android",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: [
+        "libbase",
+        "libbpf_android",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
new file mode 100644
index 0000000..1d4b524
--- /dev/null
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "GpuMem"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "gpumem/GpuMem.h"
+
+#include <android-base/stringprintf.h>
+#include <libbpf.h>
+#include <libbpf_android.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+using base::StringAppendF;
+
+GpuMem::~GpuMem() {
+    bpf_detach_tracepoint(kGpuMemTraceGroup, kGpuMemTotalTracepoint);
+}
+
+void GpuMem::initialize() {
+    // Make sure bpf programs are loaded
+    bpf::waitForProgsLoaded();
+
+    int fd = bpf::bpfFdGet(kGpuMemTotalProgPath, BPF_F_RDONLY);
+    if (fd < 0) {
+        ALOGE("Failed to retrieve pinned program from %s", kGpuMemTotalProgPath);
+        return;
+    }
+
+    // Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
+    if (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
+        ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup,
+              kGpuMemTotalTracepoint);
+        return;
+    }
+
+    // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
+    auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kGpuMemTotalMapPath);
+    if (!map.isValid()) {
+        ALOGE("Failed to create bpf map from %s", kGpuMemTotalMapPath);
+        return;
+    }
+    setGpuMemTotalMap(map);
+}
+
+void GpuMem::setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+    mGpuMemTotalMap = std::move(map);
+}
+
+// Dump the snapshots of global and per process memory usage on all gpus
+void GpuMem::dump(const Vector<String16>& /* args */, std::string* result) {
+    ATRACE_CALL();
+
+    if (!mGpuMemTotalMap.isValid()) {
+        result->append("Failed to initialize GPU memory eBPF\n");
+        return;
+    }
+
+    auto res = mGpuMemTotalMap.getFirstKey();
+    if (!res.ok()) {
+        result->append("GPU memory total usage map is empty\n");
+        return;
+    }
+    uint64_t key = res.value();
+    // unordered_map<gpu_id, vector<pair<pid, size>>>
+    std::unordered_map<uint32_t, std::vector<std::pair<uint32_t, uint64_t>>> dumpMap;
+    while (true) {
+        uint32_t gpu_id = key >> 32;
+        uint32_t pid = key;
+
+        res = mGpuMemTotalMap.readValue(key);
+        if (!res.ok()) break;
+        uint64_t size = res.value();
+
+        dumpMap[gpu_id].emplace_back(pid, size);
+
+        res = mGpuMemTotalMap.getNextKey(key);
+        if (!res.ok()) break;
+        key = res.value();
+    }
+
+    for (auto& gpu : dumpMap) {
+        if (gpu.second.empty()) continue;
+        StringAppendF(result, "Memory snapshot for GPU %u:\n", gpu.first);
+
+        std::sort(gpu.second.begin(), gpu.second.end(),
+                  [](auto& l, auto& r) { return l.first < r.first; });
+
+        int i = 0;
+        if (gpu.second[0].first != 0) {
+            StringAppendF(result, "Global total: N/A\n");
+        } else {
+            StringAppendF(result, "Global total: %" PRIu64 "\n", gpu.second[0].second);
+            i++;
+        }
+        for (; i < gpu.second.size(); i++) {
+            StringAppendF(result, "Proc %u total: %" PRIu64 "\n", gpu.second[i].first,
+                          gpu.second[i].second);
+        }
+    }
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
new file mode 100644
index 0000000..6d0322a
--- /dev/null
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <bpf/BpfMap.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class GpuMem {
+public:
+    GpuMem() = default;
+    ~GpuMem();
+
+    // initialize eBPF program and map
+    void initialize();
+    // dumpsys interface
+    void dump(const Vector<String16>& args, std::string* result);
+
+private:
+    // Friend class for testing.
+    friend class TestableGpuMem;
+
+    // set gpu memory total map
+    void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map);
+
+    // bpf map for GPU memory total data
+    android::bpf::BpfMap<uint64_t, uint64_t> mGpuMemTotalMap;
+
+    // gpu memory tracepoint event category
+    static constexpr char kGpuMemTraceGroup[] = "gpu_mem";
+    // gpu memory total tracepoint
+    static constexpr char kGpuMemTotalTracepoint[] = "gpu_mem_total";
+    // pinned gpu memory total bpf c program path in bpf sysfs
+    static constexpr char kGpuMemTotalProgPath[] =
+            "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total";
+    // pinned gpu memory total bpf map path in bpf sysfs
+    static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+};
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d0a5d44..dda04f2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -364,18 +364,16 @@
             break;
         }
     }
-    std::vector<uint8_t> data;
     const uint8_t* start = reinterpret_cast<const uint8_t*>(&event);
-    data.assign(start, start + size);
-    return sign(data);
+    return sign(start, size);
 }
 
-std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const {
+std::array<uint8_t, 32> HmacKeyManager::sign(const uint8_t* data, size_t size) const {
     // SHA256 always generates 32-bytes result
     std::array<uint8_t, 32> hash;
     unsigned int hashLen = 0;
-    uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(),
-                           hash.data(), &hashLen);
+    uint8_t* result =
+            HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data, size, hash.data(), &hashLen);
     if (result == nullptr) {
         ALOGE("Could not sign the data using HMAC");
         return INVALID_HMAC;
@@ -1981,17 +1979,48 @@
     return true;
 }
 
+/**
+ * Indicate whether one window handle should be considered as obscuring
+ * another window handle. We only check a few preconditions. Actually
+ * checking the bounds is left to the caller.
+ */
+static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle,
+                            const sp<InputWindowHandle>& otherHandle) {
+    // Compare by token so cloned layers aren't counted
+    if (haveSameToken(windowHandle, otherHandle)) {
+        return false;
+    }
+    auto info = windowHandle->getInfo();
+    auto otherInfo = otherHandle->getInfo();
+    if (!otherInfo->visible) {
+        return false;
+    } else if (info->ownerPid == otherInfo->ownerPid && otherHandle->getToken() == nullptr) {
+      // In general, if ownerPid is the same we don't want to generate occlusion
+      // events. This line is now necessary since we are including all Surfaces
+      // in occlusion calculation, so if we didn't check PID like this SurfaceView
+      // would occlude their parents. On the other hand before we started including
+      // all surfaces in occlusion calculation and had this line, we would count
+      // windows with an input channel from the same PID as occluding, and so we
+      // preserve this behavior with the getToken() == null check.
+        return false;
+    } else if (otherInfo->isTrustedOverlay()) {
+        return false;
+    } else if (otherInfo->displayId != info->displayId) {
+        return false;
+    }
+    return true;
+}
+
 bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
                                                     int32_t x, int32_t y) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
     const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
     for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
-        if (haveSameToken(otherHandle, windowHandle)) {
-            break;
+        if (windowHandle == otherHandle) {
+            break; // All future windows are below us. Exit early.
         }
-
         const InputWindowInfo* otherInfo = otherHandle->getInfo();
-        if (otherInfo->visible && !otherInfo->isTrustedOverlay() &&
+        if (canBeObscuredBy(windowHandle, otherHandle) &&
             otherInfo->frameContainsPoint(x, y)) {
             return true;
         }
@@ -2004,12 +2033,11 @@
     const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
     for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
-        if (haveSameToken(otherHandle, windowHandle)) {
-            break;
+        if (windowHandle == otherHandle) {
+            break; // All future windows are below us. Exit early.
         }
-
         const InputWindowInfo* otherInfo = otherHandle->getInfo();
-        if (otherInfo->visible && !otherInfo->isTrustedOverlay() &&
+        if (canBeObscuredBy(windowHandle, otherHandle) &&
             otherInfo->overlaps(windowInfo)) {
             return true;
         }
@@ -2444,11 +2472,8 @@
         EventEntry* eventEntry = dispatchEntry->eventEntry;
         switch (eventEntry->type) {
             case EventEntry::Type::KEY: {
-                KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-                VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(*keyEntry);
-                verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
-                verifiedEvent.action = dispatchEntry->resolvedAction;
-                std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
+                const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
+                std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
 
                 // Publish the key event.
                 status =
@@ -2500,12 +2525,8 @@
                         usingCoords = scaledCoords;
                     }
                 }
-                VerifiedMotionEvent verifiedEvent =
-                        verifiedMotionEventFromMotionEntry(*motionEntry);
-                verifiedEvent.actionMasked =
-                        dispatchEntry->resolvedAction & AMOTION_EVENT_ACTION_MASK;
-                verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS;
-                std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
+
+                std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
 
                 // Publish the motion event.
                 status = connection->inputPublisher
@@ -2585,6 +2606,28 @@
     }
 }
 
+const std::array<uint8_t, 32> InputDispatcher::getSignature(
+        const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const {
+    int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK;
+    if ((actionMasked == AMOTION_EVENT_ACTION_UP) || (actionMasked == AMOTION_EVENT_ACTION_DOWN)) {
+        // Only sign events up and down events as the purely move events
+        // are tied to their up/down counterparts so signing would be redundant.
+        VerifiedMotionEvent verifiedEvent = verifiedMotionEventFromMotionEntry(motionEntry);
+        verifiedEvent.actionMasked = actionMasked;
+        verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS;
+        return mHmacKeyManager.sign(verifiedEvent);
+    }
+    return INVALID_HMAC;
+}
+
+const std::array<uint8_t, 32> InputDispatcher::getSignature(
+        const KeyEntry& keyEntry, const DispatchEntry& dispatchEntry) const {
+    VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(keyEntry);
+    verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
+    verifiedEvent.action = dispatchEntry.resolvedAction;
+    return mHmacKeyManager.sign(verifiedEvent);
+}
+
 void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection, uint32_t seq,
                                                 bool handled) {
@@ -3273,9 +3316,8 @@
             KeyEntry* injectedEntry =
                     new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(),
                                  VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
-                                 incomingKey.getDisplayId(), policyFlags, action, flags,
-                                 incomingKey.getKeyCode(), incomingKey.getScanCode(),
-                                 incomingKey.getMetaState(), incomingKey.getRepeatCount(),
+                                 incomingKey.getDisplayId(), policyFlags, action, flags, keyCode,
+                                 incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
                                  incomingKey.getDownTime());
             injectedEntries.push(injectedEntry);
             break;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 4707bee..a3afe1e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -62,7 +62,7 @@
     std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
 
 private:
-    std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const;
+    std::array<uint8_t, 32> sign(const uint8_t* data, size_t size) const;
     const std::array<uint8_t, 128> mHmacKey;
 };
 
@@ -220,7 +220,11 @@
     // the pointer stream in order to claim it for a system gesture.
     std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock);
 
-    HmacKeyManager mHmacKeyManager;
+    const HmacKeyManager mHmacKeyManager;
+    const std::array<uint8_t, 32> getSignature(const MotionEntry& motionEntry,
+                                               const DispatchEntry& dispatchEntry) const;
+    const std::array<uint8_t, 32> getSignature(const KeyEntry& keyEntry,
+                                               const DispatchEntry& dispatchEntry) const;
 
     // Event injection and synchronization.
     std::condition_variable mInjectionResultAvailable;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index cbe0190..b56f356 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -21,6 +21,7 @@
         "InputHost.cpp",
     ],
 
+    header_libs: ["jni_headers"],
     shared_libs: [
         "libbinder",
         "libcrypto",
@@ -42,6 +43,7 @@
         //-fvisibility=hidden
     ],
 
+    export_header_lib_headers: ["jni_headers"],
     export_include_dirs: ["."],
 }
 
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index d77c8c8..43bd9f1 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -255,6 +255,7 @@
                       getDeviceName().c_str());
                 cancelTouch(when);
             }
+            continue;
         }
 
         if (outCount >= MAX_POINTERS) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 96d86b6..109edfe 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1748,7 +1748,8 @@
 
     virtual void SetUp() override {
         mFakePolicy = new FakeInputReaderPolicy();
-        mTestListener = new TestInputListener(50ms);
+        mTestListener = new TestInputListener(2000ms /*eventHappenedTimeout*/,
+                                              30ms /*eventDidNotHappenTimeout*/);
 
         mReader = new InputReader(std::make_shared<EventHub>(), mFakePolicy, mTestListener);
         ASSERT_EQ(mReader->start(), OK);
@@ -7081,6 +7082,76 @@
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
 }
 
+/**
+ * Test multi-touch should be canceled when received the MT_TOOL_PALM event from some finger,
+ * and could be allowed again after all non-MT_TOOL_PALM is release and the new point is
+ * MT_TOOL_FINGER.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    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);
+
+    // Second finger down.
+    processSlot(mapper, 1);
+    processPosition(mapper, x2, y2);
+    processId(mapper, 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // If the tool type of the first pointer changes to MT_TOOL_PALM,
+    // the entire gesture should be aborted, so we expect to receive ACTION_CANCEL.
+    processSlot(mapper, 0);
+    processId(mapper, 1);
+    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.
+    processSlot(mapper, 1);
+    processId(mapper, 2);
+    processPosition(mapper, x3, y3);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // second finger up.
+    processId(mapper, -1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // first finger move, but still in palm
+    processSlot(mapper, 0);
+    processId(mapper, 1);
+    processPosition(mapper, x1 - 1, y1 - 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // second finger down, expect as new finger down.
+    processSlot(mapper, 1);
+    processId(mapper, 2);
+    processPosition(mapper, x2, y2);
+    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);
+}
+
 // --- MultiTouchInputMapperTest_ExternalDevice ---
 
 class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 86ff3b1..9bff166 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -23,7 +23,10 @@
 
 // --- TestInputListener ---
 
-TestInputListener::TestInputListener(const std::chrono::milliseconds timeout) : mTimeout(timeout) {}
+TestInputListener::TestInputListener(std::chrono::milliseconds eventHappenedTimeout,
+                                     std::chrono::milliseconds eventDidNotHappenTimeout)
+      : mEventHappenedTimeout(eventHappenedTimeout),
+        mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {}
 
 TestInputListener::~TestInputListener() { }
 
@@ -86,9 +89,9 @@
 
     std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
     if (queue.empty()) {
-        const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) {
-            return !queue.empty();
-        });
+        const bool eventReceived =
+                mCondition.wait_for(lock, mEventHappenedTimeout,
+                                    [&queue]() REQUIRES(mLock) { return !queue.empty(); });
         if (!eventReceived) {
             FAIL() << "Timed out waiting for event: " << message.c_str();
         }
@@ -105,9 +108,9 @@
     base::ScopedLockAssertion assumeLocked(mLock);
 
     std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) {
-        return !queue.empty();
-    });
+    const bool eventReceived =
+            mCondition.wait_for(lock, mEventDidNotHappenTimeout,
+                                [&queue]() REQUIRES(mLock) { return !queue.empty(); });
     if (eventReceived) {
         FAIL() << "Unexpected event: " << message.c_str();
     }
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 4262f5a..d50c6bc 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -32,7 +32,8 @@
     virtual ~TestInputListener();
 
 public:
-    TestInputListener(const std::chrono::milliseconds timeout = 5ms);
+    TestInputListener(std::chrono::milliseconds eventHappenedTimeout = 0ms,
+                      std::chrono::milliseconds eventDidNotHappenTimeout = 0ms);
 
     void assertNotifyConfigurationChangedWasCalled(
             NotifyConfigurationChangedArgs* outEventArgs = nullptr);
@@ -75,7 +76,8 @@
 
     std::mutex mLock;
     std::condition_variable mCondition;
-    const std::chrono::milliseconds mTimeout;
+    const std::chrono::milliseconds mEventHappenedTimeout;
+    const std::chrono::milliseconds mEventDidNotHappenTimeout;
 
     std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
                std::vector<NotifyDeviceResetArgs>,          //
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index aa6f1b8..45e67f7 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -20,7 +20,6 @@
 #include "android/hardware/sensors/2.1/ISensorsCallback.h"
 #include "android/hardware/sensors/2.1/types.h"
 #include "convertV2_1.h"
-#include "SensorService.h"
 
 #include <android-base/logging.h>
 #include <android/util/ProtoOutputStream.h>
@@ -30,6 +29,7 @@
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 
+#include <cstddef>
 #include <chrono>
 #include <cinttypes>
 #include <thread>
@@ -144,11 +144,22 @@
                     sensor_t sensor;
                     convertToSensor(convertToOldSensorInfo(list[i]), &sensor);
 
-                    if (sensor.resolution == 0) {
-                        // Don't crash here or the device will go into a crashloop.
-                        ALOGE("%s must have a non-zero resolution", sensor.name);
-                        // For simple algos, map their resolution to 1 if it's not specified
-                        sensor.resolution = SensorDeviceUtils::defaultResolutionForType(sensor.type);
+                    if (sensor.type < static_cast<int>(SensorType::DEVICE_PRIVATE_BASE)) {
+                        if(sensor.resolution == 0) {
+                            // Don't crash here or the device will go into a crashloop.
+                            ALOGW("%s must have a non-zero resolution", sensor.name);
+                            // For simple algos, map their resolution to 1 if it's not specified
+                            sensor.resolution =
+                                    SensorDeviceUtils::defaultResolutionForType(sensor.type);
+                        }
+
+                        double promotedResolution = sensor.resolution;
+                        double promotedMaxRange = sensor.maxRange;
+                        if (fmod(promotedMaxRange, promotedResolution) != 0) {
+                            ALOGW("%s's max range %f is not a multiple of the resolution %f",
+                                    sensor.name, sensor.maxRange, sensor.resolution);
+                            SensorDeviceUtils::quantizeValue(&sensor.maxRange, promotedResolution);
+                        }
                     }
 
                     // Sanity check and clamp power if it is 0 (or close)
@@ -411,8 +422,8 @@
     if (mSensors == nullptr) return "HAL not initialized\n";
 
     String8 result;
-    result.appendFormat("Total %zu h/w sensors, %zu running:\n",
-                        mSensorList.size(), mActivationCount.size());
+    result.appendFormat("Total %zu h/w sensors, %zu running %zu disabled clients:\n",
+                        mSensorList.size(), mActivationCount.size(), mDisabledClients.size());
 
     Mutex::Autolock _l(mLock);
     for (const auto & s : mSensorList) {
@@ -425,16 +436,18 @@
         result.append("sampling_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
-            result.appendFormat("%.1f%s", params.mTSample / 1e6f,
-                j < info.batchParams.size() - 1 ? ", " : "");
+            result.appendFormat("%.1f%s%s", params.mTSample / 1e6f,
+                isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "",
+                (j < info.batchParams.size() - 1) ? ", " : "");
         }
         result.appendFormat("}, selected = %.2f ms; ", info.bestBatchParams.mTSample / 1e6f);
 
         result.append("batching_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
-            result.appendFormat("%.1f%s", params.mTBatch / 1e6f,
-                    j < info.batchParams.size() - 1 ? ", " : "");
+            result.appendFormat("%.1f%s%s", params.mTBatch / 1e6f,
+                    isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "",
+                    (j < info.batchParams.size() - 1) ? ", " : "");
         }
         result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f);
     }
@@ -651,7 +664,7 @@
 }
 
 status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) {
-    bool actuateHardware = false;
+    bool activateHardware = false;
 
     status_t err(NO_ERROR);
 
@@ -677,7 +690,7 @@
 
         if (info.batchParams.indexOfKey(ident) >= 0) {
             if (info.numActiveClients() > 0 && !info.isActive) {
-                actuateHardware = true;
+                activateHardware = true;
             }
         } else {
             // Log error. Every activate call should be preceded by a batch() call.
@@ -697,7 +710,7 @@
         if (info.removeBatchParamsForIdent(ident) >= 0) {
             if (info.numActiveClients() == 0) {
                 // This is the last connection, we need to de-activate the underlying h/w sensor.
-                actuateHardware = true;
+                activateHardware = true;
             } else {
                 // Call batch for this sensor with the previously calculated best effort
                 // batch_rate and timeout. One of the apps has unregistered for sensor
@@ -717,12 +730,8 @@
         }
     }
 
-    if (actuateHardware) {
-        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
-                 enabled);
-        err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
-        ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
-                 strerror(-err));
+    if (activateHardware) {
+        err = doActivateHardwareLocked(handle, enabled);
 
         if (err != NO_ERROR && enabled) {
             // Failure when enabling the sensor. Clean up on failure.
@@ -738,6 +747,15 @@
     return err;
 }
 
+status_t SensorDevice::doActivateHardwareLocked(int handle, bool enabled) {
+    ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+             enabled);
+    status_t err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
+    ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
+             strerror(-err));
+    return err;
+}
+
 status_t SensorDevice::batch(
         void* ident,
         int handle,
@@ -778,6 +796,18 @@
         info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
     }
 
+    status_t err =  updateBatchParamsLocked(handle, info);
+    if (err != NO_ERROR) {
+        ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
+              mSensors.get(), handle, info.bestBatchParams.mTSample,
+              info.bestBatchParams.mTBatch, strerror(-err));
+        info.removeBatchParamsForIdent(ident);
+    }
+
+    return err;
+}
+
+status_t SensorDevice::updateBatchParamsLocked(int handle, Info &info) {
     BatchParams prevBestBatchParams = info.bestBatchParams;
     // Find the minimum of all timeouts and batch_rates for this sensor.
     info.selectBatchParams();
@@ -795,13 +825,8 @@
                  info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
         err = checkReturnAndGetStatus(mSensors->batch(
                 handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));
-        if (err != NO_ERROR) {
-            ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
-                  mSensors.get(), handle, info.bestBatchParams.mTSample,
-                  info.bestBatchParams.mTBatch, strerror(-err));
-            info.removeBatchParamsForIdent(ident);
-        }
     }
+
     return err;
 }
 
@@ -821,13 +846,61 @@
     return checkReturnAndGetStatus(mSensors->flush(handle));
 }
 
-bool SensorDevice::isClientDisabled(void* ident) {
+bool SensorDevice::isClientDisabled(void* ident) const {
     Mutex::Autolock _l(mLock);
     return isClientDisabledLocked(ident);
 }
 
-bool SensorDevice::isClientDisabledLocked(void* ident) {
-    return mDisabledClients.indexOf(ident) >= 0;
+bool SensorDevice::isClientDisabledLocked(void* ident) const {
+    return mDisabledClients.count(ident) > 0;
+}
+
+std::vector<void *> SensorDevice::getDisabledClientsLocked() const {
+    std::vector<void *> vec;
+    for (const auto& it : mDisabledClients) {
+        vec.push_back(it.first);
+    }
+
+    return vec;
+}
+
+void SensorDevice::addDisabledReasonForIdentLocked(void* ident, DisabledReason reason) {
+    mDisabledClients[ident] |= 1 << reason;
+}
+
+void SensorDevice::removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason) {
+    if (isClientDisabledLocked(ident)) {
+        mDisabledClients[ident] &= ~(1 << reason);
+        if (mDisabledClients[ident] == 0) {
+            mDisabledClients.erase(ident);
+        }
+    }
+}
+
+void SensorDevice::setUidStateForConnection(void* ident, SensorService::UidState state) {
+    Mutex::Autolock _l(mLock);
+    if (state == SensorService::UID_STATE_ACTIVE) {
+        removeDisabledReasonForIdentLocked(ident, DisabledReason::DISABLED_REASON_UID_IDLE);
+    } else {
+        addDisabledReasonForIdentLocked(ident, DisabledReason::DISABLED_REASON_UID_IDLE);
+    }
+
+    for (size_t i = 0; i< mActivationCount.size(); ++i) {
+        int handle = mActivationCount.keyAt(i);
+        Info& info = mActivationCount.editValueAt(i);
+
+        if (info.hasBatchParamsForIdent(ident)) {
+            if (updateBatchParamsLocked(handle, info) != NO_ERROR) {
+                bool enable = info.numActiveClients() == 0 && info.isActive;
+                bool disable = info.numActiveClients() > 0 && !info.isActive;
+
+                if ((enable || disable) &&
+                    doActivateHardwareLocked(handle, enable) == NO_ERROR) {
+                    info.isActive = enable;
+                }
+            }
+        }
+    }
 }
 
 bool SensorDevice::isSensorActive(int handle) const {
@@ -842,8 +915,12 @@
 void SensorDevice::enableAllSensors() {
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
-    mDisabledClients.clear();
-    ALOGI("cleared mDisabledClients");
+
+    for (void *client : getDisabledClientsLocked()) {
+        removeDisabledReasonForIdentLocked(
+            client, DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
+    }
+
     for (size_t i = 0; i< mActivationCount.size(); ++i) {
         Info& info = mActivationCount.editValueAt(i);
         if (info.batchParams.isEmpty()) continue;
@@ -883,7 +960,8 @@
            // Add all the connections that were registered for this sensor to the disabled
            // clients list.
            for (size_t j = 0; j < info.batchParams.size(); ++j) {
-               mDisabledClients.add(info.batchParams.keyAt(j));
+               addDisabledReasonForIdentLocked(
+                   info.batchParams.keyAt(j), DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
                ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
            }
 
@@ -1058,7 +1136,7 @@
 
 void SensorDevice::notifyConnectionDestroyed(void* ident) {
     Mutex::Autolock _l(mLock);
-    mDisabledClients.remove(ident);
+    mDisabledClients.erase(ident);
 }
 
 bool SensorDevice::isDirectReportSupported() const {
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 04e6031..5e7d3da 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -18,6 +18,7 @@
 #define ANDROID_SENSOR_DEVICE_H
 
 #include "SensorDeviceUtils.h"
+#include "SensorService.h"
 #include "SensorServiceUtils.h"
 #include "ISensorsWrapper.h"
 
@@ -116,6 +117,8 @@
     hardware::Return<void> onDynamicSensorsDisconnected(
             const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
 
+    void setUidStateForConnection(void* ident, SensorService::UidState state);
+
     bool isReconnecting() const {
         return mReconnecting;
     }
@@ -179,6 +182,13 @@
         // the removed ident. If index >=0, ident is present and successfully removed.
         ssize_t removeBatchParamsForIdent(void* ident);
 
+        bool hasBatchParamsForIdent(void* ident) const {
+            return batchParams.indexOfKey(ident) >= 0;
+        }
+
+        /**
+         * @return The number of active clients of this sensor.
+         */
         int numActiveClients() const;
     };
     DefaultKeyedVector<int, Info> mActivationCount;
@@ -187,8 +197,26 @@
     SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
     int mTotalHidlTransportErrors;
 
-    // Use this vector to determine which client is activated or deactivated.
-    SortedVector<void *> mDisabledClients;
+    /**
+     * Enums describing the reason why a client was disabled.
+     */
+    enum DisabledReason : uint8_t {
+        // UID becomes idle (e.g. app goes to background).
+        DISABLED_REASON_UID_IDLE = 0,
+
+        // Sensors are restricted for all clients.
+        DISABLED_REASON_SERVICE_RESTRICTED,
+        DISABLED_REASON_MAX,
+    };
+
+    static_assert(DisabledReason::DISABLED_REASON_MAX < sizeof(uint8_t) * CHAR_BIT);
+
+    // Use this map to determine which client is activated or deactivated.
+    std::unordered_map<void *, uint8_t> mDisabledClients;
+
+    void addDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
+    void removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
+
     SensorDevice();
     bool connectHidlService();
     void initializeSensorList();
@@ -214,6 +242,9 @@
     status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
                          int64_t maxBatchReportLatencyNs);
 
+    status_t updateBatchParamsLocked(int handle, Info& info);
+    status_t doActivateHardwareLocked(int handle, bool enable);
+
     void handleHidlDeath(const std::string &detail);
     template<typename T>
     void checkReturn(const Return<T>& ret) {
@@ -225,8 +256,11 @@
     //TODO(b/67425500): remove waiter after bug is resolved.
     sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
 
-    bool isClientDisabled(void* ident);
-    bool isClientDisabledLocked(void* ident);
+    bool isClientDisabled(void* ident) const;
+    bool isClientDisabledLocked(void* ident) const;
+    std::vector<void *> getDisabledClientsLocked() const;
+
+    bool clientHasNoAccessLocked(void* ident) const;
 
     using Event = hardware::sensors::V2_1::Event;
     using SensorInfo = hardware::sensors::V2_1::SensorInfo;
diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp
index 6bf62e4..0dcf8c0 100644
--- a/services/sensorservice/SensorDeviceUtils.cpp
+++ b/services/sensorservice/SensorDeviceUtils.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 
 #include <chrono>
-#include <cmath>
 #include <thread>
 
 using ::android::hardware::Void;
@@ -30,17 +29,6 @@
 
 namespace android {
 namespace SensorDeviceUtils {
-namespace {
-
-inline void quantizeValue(float *value, double resolution) {
-    // Increase the value of the sensor's nominal resolution to ensure that
-    // sensor accuracy improvements, like runtime calibration, are not masked
-    // during requantization.
-    double incRes = 0.25 * resolution;
-    *value = round(static_cast<double>(*value) / incRes) * incRes;
-}
-
-}  // namespace
 
 void quantizeSensorEventValues(sensors_event_t *event, float resolution) {
     LOG_FATAL_IF(resolution == 0, "Resolution must be specified for all sensors!");
diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h
index b66542c..d7e621c 100644
--- a/services/sensorservice/SensorDeviceUtils.h
+++ b/services/sensorservice/SensorDeviceUtils.h
@@ -20,6 +20,7 @@
 #include <android/hidl/manager/1.0/IServiceNotification.h>
 #include <hardware/sensors.h>
 
+#include <cmath>
 #include <condition_variable>
 #include <thread>
 
@@ -30,6 +31,15 @@
 namespace android {
 namespace SensorDeviceUtils {
 
+// Quantizes a single value using a sensor's resolution.
+inline void quantizeValue(float *value, double resolution) {
+    // Increase the value of the sensor's nominal resolution to ensure that
+    // sensor accuracy improvements, like runtime calibration, are not masked
+    // during requantization.
+    double incRes = 0.25 * resolution;
+    *value = round(static_cast<double>(*value) / incRes) * incRes;
+}
+
 // Ensures a sensor event doesn't provide values finer grained than its sensor resolution allows.
 void quantizeSensorEventValues(sensors_event_t *event, float resolution);
 
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 106efd6..e4c33da 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -93,6 +93,18 @@
     return nullptr;
 }
 
+void SensorService::SensorDirectConnection::onSensorAccessChanged(bool hasAccess) {
+    if (!hasAccess) {
+        stopAll(true /* backupRecord */);
+    } else {
+        recoverAll();
+    }
+}
+
+bool SensorService::SensorDirectConnection::hasSensorAccess() const {
+    return mService->hasSensorAccess(mUid, mOpPackageName);
+}
+
 status_t SensorService::SensorDirectConnection::enableDisable(
         int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
         int reservedFlags) {
@@ -125,7 +137,7 @@
         return NO_ERROR;
     }
 
-    if (!mService->isOperationPermitted(mOpPackageName)) {
+    if (!hasSensorAccess()) {
         return PERMISSION_DENIED;
     }
 
@@ -169,12 +181,15 @@
 }
 
 void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
+    Mutex::Autolock _l(mConnectionLock);
+    stopAllLocked(backupRecord);
+}
 
+void SensorService::SensorDirectConnection::stopAllLocked(bool backupRecord) {
     struct sensors_direct_cfg_t config = {
         .rate_level = SENSOR_DIRECT_RATE_STOP
     };
 
-    Mutex::Autolock _l(mConnectionLock);
     SensorDevice& dev(SensorDevice::getInstance());
     for (auto &i : mActivated) {
         dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
@@ -187,21 +202,25 @@
 }
 
 void SensorService::SensorDirectConnection::recoverAll() {
-    stopAll(false);
-
     Mutex::Autolock _l(mConnectionLock);
-    SensorDevice& dev(SensorDevice::getInstance());
+    if (!mActivatedBackup.empty()) {
+        stopAllLocked(false);
 
-    // recover list of report from backup
-    mActivated = mActivatedBackup;
-    mActivatedBackup.clear();
+        SensorDevice& dev(SensorDevice::getInstance());
 
-    // re-enable them
-    for (auto &i : mActivated) {
-        struct sensors_direct_cfg_t config = {
-            .rate_level = i.second
-        };
-        dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+        // recover list of report from backup
+        ALOG_ASSERT(mActivated.empty(),
+                    "mActivated must be empty if mActivatedBackup was non-empty");
+        mActivated = mActivatedBackup;
+        mActivatedBackup.clear();
+
+        // re-enable them
+        for (auto &i : mActivated) {
+            struct sensors_direct_cfg_t config = {
+                .rate_level = i.second
+            };
+            dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+        }
     }
 }
 
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index ead08d3..4181b65 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -42,17 +42,14 @@
     void dump(String8& result) const;
     void dump(util::ProtoOutputStream* proto) const;
     uid_t getUid() const { return mUid; }
+    const String16& getOpPackageName() const { return mOpPackageName; }
     int32_t getHalChannelHandle() const;
     bool isEquivalent(const sensors_direct_mem_t *mem) const;
 
-    // stop all active sensor report. if backupRecord is set to false,
-    // those report can be recovered by recoverAll
-    // called by SensorService when enter restricted mode
-    void stopAll(bool backupRecord = false);
-
-    // recover sensor reports previously stopped by stopAll(true)
-    // called by SensorService when return to NORMAL mode.
-    void recoverAll();
+    // Invoked when access to sensors for this connection has changed, e.g. lost or
+    // regained due to changes in the sensor restricted/privacy mode or the
+    // app changed to idle/active status.
+    void onSensorAccessChanged(bool hasAccess);
 
 protected:
     virtual ~SensorDirectConnection();
@@ -66,6 +63,25 @@
     virtual int32_t configureChannel(int handle, int rateLevel);
     virtual void destroy();
 private:
+    bool hasSensorAccess() const;
+
+    // Stops all active sensor direct report requests.
+    //
+    // If backupRecord is true, stopped requests can be recovered
+    // by a subsequent recoverAll() call (e.g. when temporarily stopping
+    // sensors for sensor privacy/restrict mode or when an app becomes
+    // idle).
+    void stopAll(bool backupRecord = false);
+    // Same as stopAll() but with mConnectionLock held.
+    void stopAllLocked(bool backupRecord);
+
+    // Recover sensor requests previously stopped by stopAll(true).
+    // This method can be called when a sensor access resumes (e.g.
+    // sensor privacy/restrict mode lifted or app becomes active).
+    //
+    // If no requests are backed up by stopAll(), this method is no-op.
+    void recoverAll();
+
     const sp<SensorService> mService;
     const uid_t mUid;
     const sensors_direct_mem_t mMem;
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index e799372..ccf05d9 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -31,12 +31,11 @@
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
-        const String16& opPackageName, bool hasSensorAccess)
+        const String16& opPackageName)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
       mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
-      mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false),
-      mHasSensorAccess(hasSensorAccess) {
+      mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false) {
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -431,13 +430,9 @@
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
-void SensorService::SensorEventConnection::setSensorAccess(const bool hasAccess) {
-    Mutex::Autolock _l(mConnectionLock);
-    mHasSensorAccess = hasAccess;
-}
-
 bool SensorService::SensorEventConnection::hasSensorAccess() {
-    return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
+    return mService->isUidActive(mUid)
+        && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
 }
 
 bool SensorService::SensorEventConnection::noteOpIfRequired(const sensors_event_t& event) {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 1ca35c0..13cee6f 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -49,8 +49,7 @@
 
 public:
     SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
-                          bool isDataInjectionMode, const String16& opPackageName,
-                          bool hasSensorAccess);
+                          bool isDataInjectionMode, const String16& opPackageName);
 
     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
                         wp<const SensorEventConnection> const * mapFlushEventsToConnections = nullptr);
@@ -69,8 +68,6 @@
 
     uid_t getUid() const { return mUid; }
 
-    void setSensorAccess(const bool hasAccess);
-
 private:
     virtual ~SensorEventConnection();
     virtual void onFirstRef();
@@ -185,7 +182,6 @@
 
     mutable Mutex mDestroyLock;
     bool mDestroyed;
-    bool mHasSensorAccess;
 
     // Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
     // valid mapping for sensors that require a permission in order to reduce the lookup time.
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 5fdc74f..ffcd0a0 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -299,13 +299,33 @@
     }
 }
 
-void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
+void SensorService::onUidStateChanged(uid_t uid, UidState state) {
+    SensorDevice& dev(SensorDevice::getInstance());
+
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
         if (conn->getUid() == uid) {
-            conn->setSensorAccess(hasAccess);
+            dev.setUidStateForConnection(conn.get(), state);
         }
     }
+
+    for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+        if (conn->getUid() == uid) {
+            // Update sensor subscriptions if needed
+            bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
+            conn->onSensorAccessChanged(hasAccess);
+        }
+    }
+}
+
+bool SensorService::hasSensorAccess(uid_t uid, const String16& opPackageName) {
+    Mutex::Autolock _l(mLock);
+    return hasSensorAccessLocked(uid, opPackageName);
+}
+
+bool SensorService::hasSensorAccessLocked(uid_t uid, const String16& opPackageName) {
+    return !mSensorPrivacyPolicy->isSensorPrivacyEnabled()
+        && isUidActive(uid) && !isOperationRestrictedLocked(opPackageName);
 }
 
 const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) {
@@ -638,8 +658,9 @@
 
 void SensorService::disableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
     SensorDevice& dev(SensorDevice::getInstance());
-    for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
-        connection->stopAll(true /* backupRecord */);
+    for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
+        bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
+        conn->onSensorAccessChanged(hasAccess);
     }
     dev.disableAllSensors();
     // Clear all pending flush connections for all active sensors. If one of the active
@@ -666,8 +687,9 @@
     }
     SensorDevice& dev(SensorDevice::getInstance());
     dev.enableAllSensors();
-    for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
-        connection->recoverAll();
+    for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
+        bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
+        conn->onSensorAccessChanged(hasAccess);
     }
 }
 
@@ -1234,9 +1256,8 @@
             (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
     String16 connOpPackageName =
             (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
-    bool hasSensorAccess = mUidPolicy->isUidActive(uid);
     sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
-            requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
+            requestedMode == DATA_INJECTION, connOpPackageName));
     if (requestedMode == DATA_INJECTION) {
         mConnectionHolder.addEventConnectionIfNotPresent(result);
         // Add the associated file descriptor to the Looper for polling whenever there is data to
@@ -1887,13 +1908,12 @@
     return (packageName.contains(mWhiteListedPackage.string()));
 }
 
-bool SensorService::isOperationPermitted(const String16& opPackageName) {
-    Mutex::Autolock _l(mLock);
+bool SensorService::isOperationRestrictedLocked(const String16& opPackageName) {
     if (mCurrentOperatingMode == RESTRICTED) {
         String8 package(opPackageName);
-        return isWhiteListedPackage(package);
+        return !isWhiteListedPackage(package);
     }
-    return true;
+    return false;
 }
 
 void SensorService::UidPolicy::registerSelf() {
@@ -1921,7 +1941,7 @@
     }
     sp<SensorService> service = mService.promote();
     if (service != nullptr) {
-        service->setSensorAccess(uid, true);
+        service->onUidStateChanged(uid, UID_STATE_ACTIVE);
     }
 }
 
@@ -1936,7 +1956,7 @@
     if (deleted) {
         sp<SensorService> service = mService.promote();
         if (service != nullptr) {
-            service->setSensorAccess(uid, false);
+            service->onUidStateChanged(uid, UID_STATE_IDLE);
         }
     }
 }
@@ -1964,7 +1984,7 @@
     if (wasActive != isActive) {
         sp<SensorService> service = mService.promote();
         if (service != nullptr) {
-            service->setSensorAccess(uid, isActive);
+            service->onUidStateChanged(uid, isActive ? UID_STATE_ACTIVE : UID_STATE_IDLE);
         }
     }
 }
@@ -1990,6 +2010,10 @@
     return mActiveUids.find(uid) != mActiveUids.end();
 }
 
+bool SensorService::isUidActive(uid_t uid) {
+    return mUidPolicy->isUidActive(uid);
+}
+
 void SensorService::SensorPrivacyPolicy::registerSelf() {
     SensorPrivacyManager spm;
     mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 7d17dda..3bb8421 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -75,6 +75,11 @@
     class SensorDirectConnection;
 
 public:
+    enum UidState {
+      UID_STATE_ACTIVE = 0,
+      UID_STATE_IDLE,
+    };
+
     void cleanupConnection(SensorEventConnection* connection);
     void cleanupConnection(SensorDirectConnection* c);
 
@@ -194,6 +199,8 @@
             std::unordered_map<uid_t, bool> mOverrideUids;
     };
 
+    bool isUidActive(uid_t uid);
+
     // Sensor privacy allows a user to disable access to all sensors on the device. When
     // enabled sensor privacy will prevent all apps, including active apps, from accessing
     // sensors, they will not receive trigger nor on-change events, flush event behavior
@@ -332,7 +339,11 @@
     // allowed to register for or call flush on sensors. Typically only cts test packages are
     // allowed.
     bool isWhiteListedPackage(const String8& packageName);
-    bool isOperationPermitted(const String16& opPackageName);
+
+    // Returns true if a connection with the specified opPackageName has no access to sensors
+    // in the RESTRICTED mode (i.e. the service is in RESTRICTED mode, and the package is not
+    // whitelisted). mLock must be held to invoke this method.
+    bool isOperationRestrictedLocked(const String16& opPackageName);
 
     // Reset the state of SensorService to NORMAL mode.
     status_t resetToNormalMode();
@@ -349,7 +360,13 @@
     void enableSchedFifoMode();
 
     // Sets whether the given UID can get sensor data
-    void setSensorAccess(uid_t uid, bool hasAccess);
+    void onUidStateChanged(uid_t uid, UidState state);
+
+    // Returns true if a connection with the given uid and opPackageName
+    // currently has access to sensors.
+    bool hasSensorAccess(uid_t uid, const String16& opPackageName);
+    // Same as hasSensorAccess but with mLock held.
+    bool hasSensorAccessLocked(uid_t uid, const String16& opPackageName);
 
     // Overrides the UID state as if it is idle
     status_t handleSetUidState(Vector<String16>& args, int err);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index c6f1f7e..0182937 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -44,7 +44,6 @@
         "libGLESv1_CM",
         "libGLESv2",
         "libgui",
-        "libhardware",
         "libhidlbase",
         "liblayers_proto",
         "liblog",
@@ -287,6 +286,7 @@
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
         "libhidlbase",
+        "libui",
     ],
     export_static_lib_headers: [
         "SurfaceFlingerProperties",
diff --git a/services/surfaceflinger/Barrier.h b/services/surfaceflinger/Barrier.h
deleted file mode 100644
index 97028a8..0000000
--- a/services/surfaceflinger/Barrier.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_BARRIER_H
-#define ANDROID_BARRIER_H
-
-#include <stdint.h>
-#include <condition_variable>
-#include <mutex>
-
-namespace android {
-
-class Barrier
-{
-public:
-    // Release any threads waiting at the Barrier.
-    // Provides release semantics: preceding loads and stores will be visible
-    // to other threads before they wake up.
-    void open() {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mIsOpen = true;
-        mCondition.notify_all();
-    }
-
-    // Reset the Barrier, so wait() will block until open() has been called.
-    void close() {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mIsOpen = false;
-    }
-
-    // Wait until the Barrier is OPEN.
-    // Provides acquire semantics: no subsequent loads or stores will occur
-    // until wait() returns.
-    void wait() const {
-        std::unique_lock<std::mutex> lock(mMutex);
-        mCondition.wait(lock, [this]() NO_THREAD_SAFETY_ANALYSIS { return mIsOpen; });
-    }
-private:
-    mutable std::mutex mMutex;
-    mutable std::condition_variable mCondition;
-    int mIsOpen GUARDED_BY(mMutex){false};
-};
-
-}; // namespace android
-
-#endif // ANDROID_BARRIER_H
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index e50a909..648d129 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -407,8 +407,17 @@
 }
 
 Rect BufferLayerConsumer::getCurrentCropLocked() const {
+    uint32_t width = mDefaultWidth;
+    uint32_t height = mDefaultHeight;
+    // If the buffer comes with a rotated bit for 90 (or 270) degrees, switch width/height in order
+    // to scale and crop correctly.
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        width = mDefaultHeight;
+        height = mDefaultWidth;
+    }
+
     return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
-            ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+            ? GLConsumer::scaleDownCrop(mCurrentCrop, width, height)
             : mCurrentCrop;
 }
 
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index fb72ab8..78bbcba 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -93,11 +93,6 @@
                                          uint32_t* outTransformHint) {
     if (mFlinger->authenticateSurfaceTexture(parent) == false) {
         ALOGE("failed to authenticate surface texture");
-        // The extra parent layer check below before returning is to help with debugging
-        // b/134888387. Once the bug is fixed the check can be deleted.
-        if ((static_cast<MonitoredProducer*>(parent.get()))->getLayer() == nullptr) {
-            ALOGE("failed to find parent layer");
-        }
         return BAD_VALUE;
     }
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 5f42b54..75a4fec 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -56,7 +56,7 @@
                  status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
                           ui::Dataspace));
     MOCK_METHOD1(presentAndGetReleaseFences, status_t(DisplayId));
-    MOCK_METHOD2(setPowerMode, status_t(DisplayId, int));
+    MOCK_METHOD2(setPowerMode, status_t(DisplayId, hal::PowerMode));
     MOCK_METHOD2(setActiveConfig, status_t(DisplayId, size_t));
     MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
     MOCK_METHOD1(disconnectDisplay, void(DisplayId));
@@ -74,7 +74,7 @@
     MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(DisplayId, bool, uint8_t, uint64_t));
     MOCK_METHOD4(getDisplayedContentSample,
                  status_t(DisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
-    MOCK_METHOD2(setDisplayBrightness, status_t(DisplayId, float));
+    MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(DisplayId, float));
     MOCK_METHOD2(getDisplayBrightnessSupport, status_t(DisplayId, bool*));
 
     MOCK_METHOD2(onHotplug,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 266f91d..bdacb22 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -716,9 +716,9 @@
     }
 
     void expectSetColorCall() {
-        hwc_color_t color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
-                             static_cast<uint8_t>(std::round(kColor.g * 255)),
-                             static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
+        const hal::Color color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
+                                  static_cast<uint8_t>(std::round(kColor.g * 255)),
+                                  static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
 
         EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError));
     }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b81eb18..9af9cad 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -43,6 +43,8 @@
 
 namespace android {
 
+namespace hal = hardware::graphics::composer::hal;
+
 using android::base::StringAppendF;
 
 ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
@@ -119,17 +121,17 @@
 }
 
 // ----------------------------------------------------------------------------
-void DisplayDevice::setPowerMode(int mode) {
+void DisplayDevice::setPowerMode(hal::PowerMode mode) {
     mPowerMode = mode;
-    getCompositionDisplay()->setCompositionEnabled(mPowerMode != HWC_POWER_MODE_OFF);
+    getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
 }
 
-int DisplayDevice::getPowerMode()  const {
+hal::PowerMode DisplayDevice::getPowerMode() const {
     return mPowerMode;
 }
 
 bool DisplayDevice::isPoweredOn() const {
-    return mPowerMode != HWC_POWER_MODE_OFF;
+    return mPowerMode != hal::PowerMode::OFF;
 }
 
 void DisplayDevice::setActiveConfig(HwcConfigIndexType mode) {
@@ -262,7 +264,8 @@
     StringAppendF(&result, "+ %s\n", getDebugName().c_str());
 
     result.append("   ");
-    StringAppendF(&result, "powerMode=%d, ", mPowerMode);
+    StringAppendF(&result, "powerMode=%s (%d), ", to_string(mPowerMode).c_str(),
+                  static_cast<int32_t>(mPowerMode));
     StringAppendF(&result, "activeConfig=%d, ", mActiveConfig.value());
     getCompositionDisplay()->dump(result);
 }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 2b19cc5..8c86153 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -24,7 +24,6 @@
 #include <android/native_window.h>
 #include <binder/IBinder.h>
 #include <gui/LayerState.h>
-#include <hardware/hwcomposer_defs.h>
 #include <math/mat4.h>
 #include <renderengine/RenderEngine.h>
 #include <system/window.h>
@@ -136,8 +135,8 @@
     /* ------------------------------------------------------------------------
      * Display power mode management.
      */
-    int getPowerMode() const;
-    void setPowerMode(int mode);
+    hardware::graphics::composer::hal::PowerMode getPowerMode() const;
+    void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
     bool isPoweredOn() const;
 
     ui::Dataspace getCompositionDataSpace() const;
@@ -173,7 +172,8 @@
 
     static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
 
-    int mPowerMode = HWC_POWER_MODE_OFF;
+    hardware::graphics::composer::hal::PowerMode mPowerMode =
+            hardware::graphics::composer::hal::PowerMode::OFF;
     HwcConfigIndexType mActiveConfig;
 
     // TODO(b/74619554): Remove special cases for primary display.
@@ -184,7 +184,7 @@
     struct Physical {
         DisplayId id;
         DisplayConnectionType type;
-        android::hardware::graphics::composer::hal::HWDisplayId hwcDisplayId;
+        hardware::graphics::composer::hal::HWDisplayId hwcDisplayId;
 
         bool operator==(const Physical& other) const {
             return id == other.id && type == other.type && hwcDisplayId == other.hwcDisplayId;
@@ -228,7 +228,8 @@
     HdrCapabilities hdrCapabilities;
     int32_t supportedPerFrameMetadata{0};
     std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
-    int initialPowerMode{HWC_POWER_MODE_NORMAL};
+    hardware::graphics::composer::hal::PowerMode initialPowerMode{
+            hardware::graphics::composer::hal::PowerMode::ON};
     bool isPrimary{false};
 };
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index f9281a7..52a6380 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -92,6 +92,10 @@
         info.manufactureOrModelDate = date;
     }
 
+    if (edid.cea861Block && edid.cea861Block->hdmiVendorDataBlock) {
+        const auto& address = edid.cea861Block->hdmiVendorDataBlock->physicalAddress;
+        info.relativeAddress = {address.a, address.b, address.c, address.d};
+    }
     return info;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index fc2f72e..4819d1d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -26,6 +26,9 @@
 #include <ui/DeviceProductInfo.h>
 #include <ui/PhysicalDisplayId.h>
 
+#define LEGACY_DISPLAY_TYPE_PRIMARY 0
+#define LEGACY_DISPLAY_TYPE_EXTERNAL 1
+
 namespace android {
 
 struct DisplayId {
@@ -70,7 +73,7 @@
 };
 
 struct HdmiVendorDataBlock {
-    std::optional<HdmiPhysicalAddress> physicalAddress;
+    HdmiPhysicalAddress physicalAddress;
 };
 
 struct Cea861ExtensionBlock : ExtensionBlock {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index d6dbd57..0ea3340 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -25,7 +25,6 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "HWC2.h"
-#include "ComposerHal.h"
 
 #include <ui/Fence.h>
 #include <ui/FloatRect.h>
@@ -38,6 +37,9 @@
 #include <iterator>
 #include <set>
 
+#include "../Promise.h"
+#include "ComposerHal.h"
+
 namespace android {
 
 using android::Fence;
@@ -640,12 +642,14 @@
     return error;
 }
 
-Error Display::setDisplayBrightness(float brightness) const {
-    const auto intError = mComposer.setDisplayBrightness(mId, brightness);
-    return static_cast<Error>(intError);
+std::future<Error> Display::setDisplayBrightness(float brightness) {
+    return promise::defer([composer = &mComposer, id = mId, brightness] {
+        const auto intError = composer->setDisplayBrightness(id, brightness);
+        return static_cast<Error>(intError);
+    });
 }
 
-Error Display::setAutoLowLatencyMode(bool on) const {
+Error Display::setAutoLowLatencyMode(bool on) {
     auto intError = mComposer.setAutoLowLatencyMode(mId, on);
     return static_cast<Error>(intError);
 }
@@ -659,7 +663,7 @@
     return static_cast<Error>(intError);
 }
 
-Error Display::setContentType(ContentType contentType) const {
+Error Display::setContentType(ContentType contentType) {
     auto intError = mComposer.setContentType(mId, contentType);
     return static_cast<Error>(intError);
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index af31df8..f4c7fdd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -27,6 +27,7 @@
 #include <utils/Timers.h>
 
 #include <functional>
+#include <future>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -221,18 +222,18 @@
     [[clang::warn_unused_result]] virtual hal::Error presentOrValidate(
             uint32_t* outNumTypes, uint32_t* outNumRequests,
             android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setDisplayBrightness(
-            float brightness) const = 0;
+    [[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
+            float brightness) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getDisplayVsyncPeriod(
             nsecs_t* outVsyncPeriod) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
             const std::shared_ptr<const HWC2::Display::Config>& config,
             const hal::VsyncPeriodChangeConstraints& constraints,
             hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) const = 0;
+    [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>*) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) const = 0;
+    [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
 };
 
 namespace impl {
@@ -294,16 +295,16 @@
     hal::Error presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
                                  android::sp<android::Fence>* outPresentFence,
                                  uint32_t* state) override;
-    hal::Error setDisplayBrightness(float brightness) const override;
+    std::future<hal::Error> setDisplayBrightness(float brightness) override;
     hal::Error getDisplayVsyncPeriod(nsecs_t* outVsyncPeriod) const override;
     hal::Error setActiveConfigWithConstraints(
             const std::shared_ptr<const HWC2::Display::Config>& config,
             const hal::VsyncPeriodChangeConstraints& constraints,
             hal::VsyncPeriodChangeTimeline* outTimeline) override;
-    hal::Error setAutoLowLatencyMode(bool on) const override;
+    hal::Error setAutoLowLatencyMode(bool on) override;
     hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>* outSupportedContentTypes) const override;
-    hal::Error setContentType(hal::ContentType contentType) const override;
+    hal::Error setContentType(hal::ContentType) override;
     // Other Display methods
     hal::HWDisplayId getId() const override { return mId; }
     bool isConnected() const override { return mIsConnected; }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2f59469..038cec4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -36,6 +36,7 @@
 #include <utils/Trace.h>
 
 #include "../Layer.h" // needed only for debugging
+#include "../Promise.h"
 #include "../SurfaceFlinger.h"
 #include "ComposerHal.h"
 #include "HWC2.h"
@@ -593,7 +594,7 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) {
+status_t HWComposer::setPowerMode(DisplayId displayId, hal::PowerMode mode) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     const auto& displayData = mDisplayData[displayId];
@@ -602,7 +603,6 @@
         return INVALID_OPERATION;
     }
 
-    auto mode = static_cast<hal::PowerMode>(intMode);
     if (mode == hal::PowerMode::OFF) {
         setVsyncEnabled(displayId, hal::Vsync::DISABLE);
     }
@@ -795,17 +795,21 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::setDisplayBrightness(DisplayId displayId, float brightness) {
-    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
-    const auto error = mDisplayData[displayId].hwcDisplay->setDisplayBrightness(brightness);
-    if (error == hal::Error::UNSUPPORTED) {
-        RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
-    }
-    if (error == hal::Error::BAD_PARAMETER) {
-        RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
-    }
-    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
-    return NO_ERROR;
+std::future<status_t> HWComposer::setDisplayBrightness(DisplayId displayId, float brightness) {
+    RETURN_IF_INVALID_DISPLAY(displayId, promise::yield<status_t>(BAD_INDEX));
+    auto& display = mDisplayData[displayId].hwcDisplay;
+
+    return promise::chain(display->setDisplayBrightness(brightness))
+            .then([displayId](hal::Error error) -> status_t {
+                if (error == hal::Error::UNSUPPORTED) {
+                    RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+                }
+                if (error == hal::Error::BAD_PARAMETER) {
+                    RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+                }
+                RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+                return NO_ERROR;
+            });
 }
 
 bool HWComposer::isUsingVrComposer() const {
@@ -927,7 +931,7 @@
             } else {
                 ALOGW_IF(hasDisplayIdentificationData,
                          "Ignoring identification data for display %" PRIu64, hwcDisplayId);
-                port = isPrimary ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL;
+                port = isPrimary ? LEGACY_DISPLAY_TYPE_PRIMARY : LEGACY_DISPLAY_TYPE_EXTERNAL;
             }
 
             return DisplayIdentificationInfo{.id = getFallbackDisplayId(port),
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 431b8e2..b7e9f3a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -18,6 +18,7 @@
 #define ANDROID_SF_HWCOMPOSER_H
 
 #include <cstdint>
+#include <future>
 #include <memory>
 #include <mutex>
 #include <optional>
@@ -116,7 +117,7 @@
     virtual status_t presentAndGetReleaseFences(DisplayId displayId) = 0;
 
     // set power mode
-    virtual status_t setPowerMode(DisplayId displayId, int mode) = 0;
+    virtual status_t setPowerMode(DisplayId displayId, hal::PowerMode mode) = 0;
 
     // Sets a color transform to be applied to the result of composition
     virtual status_t setColorTransform(DisplayId displayId, const mat4& transform) = 0;
@@ -163,7 +164,7 @@
                                                DisplayedFrameStats* outStats) = 0;
 
     // Sets the brightness of a display.
-    virtual status_t setDisplayBrightness(DisplayId displayId, float brightness) = 0;
+    virtual std::future<status_t> setDisplayBrightness(DisplayId displayId, float brightness) = 0;
 
     // Events handling ---------------------------------------------------------
 
@@ -263,7 +264,7 @@
     status_t presentAndGetReleaseFences(DisplayId displayId) override;
 
     // set power mode
-    status_t setPowerMode(DisplayId displayId, int mode) override;
+    status_t setPowerMode(DisplayId displayId, hal::PowerMode mode) override;
 
     // Sets a color transform to be applied to the result of composition
     status_t setColorTransform(DisplayId displayId, const mat4& transform) override;
@@ -305,7 +306,7 @@
                                               uint8_t componentMask, uint64_t maxFrames) override;
     status_t getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, uint64_t timestamp,
                                        DisplayedFrameStats* outStats) override;
-    status_t setDisplayBrightness(DisplayId displayId, float brightness) override;
+    std::future<status_t> setDisplayBrightness(DisplayId displayId, float brightness) override;
 
     // Events handling ---------------------------------------------------------
 
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index ac3917d..66ee425 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -152,12 +152,14 @@
     switch (mode) {
         case hardware::graphics::composer::hal::PowerMode::OFF:
             return "Off";
-        case hardware::graphics::composer::hal::PowerMode::DOZE_SUSPEND:
-            return "DozeSuspend";
         case hardware::graphics::composer::hal::PowerMode::DOZE:
             return "Doze";
         case hardware::graphics::composer::hal::PowerMode::ON:
             return "On";
+        case hardware::graphics::composer::hal::PowerMode::DOZE_SUSPEND:
+            return "DozeSuspend";
+        case hardware::graphics::composer::hal::PowerMode::ON_SUSPEND:
+            return "OnSuspend";
         default:
             return "Unknown";
     }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8452957..fe59d73 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1532,17 +1532,33 @@
 void Layer::miniDumpHeader(std::string& result) {
     result.append("-------------------------------");
     result.append("-------------------------------");
-    result.append("-----------------------------\n");
+    result.append("-------------------------------");
+    result.append("-------------------------------");
+    result.append("---------\n");
     result.append(" Layer name\n");
     result.append("           Z | ");
     result.append(" Window Type | ");
     result.append(" Comp Type | ");
     result.append(" Transform | ");
     result.append("  Disp Frame (LTRB) | ");
-    result.append("         Source Crop (LTRB)\n");
+    result.append("         Source Crop (LTRB) | ");
+    result.append("    Frame Rate (Explicit)\n");
     result.append("-------------------------------");
     result.append("-------------------------------");
-    result.append("-----------------------------\n");
+    result.append("-------------------------------");
+    result.append("-------------------------------");
+    result.append("---------\n");
+}
+
+std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) {
+    switch (compatibility) {
+        case FrameRateCompatibility::Default:
+            return "Default";
+        case FrameRateCompatibility::ExactOrMultiple:
+            return "ExactOrMultiple";
+        case FrameRateCompatibility::NoVote:
+            return "NoVote";
+    }
 }
 
 void Layer::miniDump(std::string& result, const sp<DisplayDevice>& displayDevice) const {
@@ -1578,12 +1594,21 @@
     const Rect& frame = outputLayerState.displayFrame;
     StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
     const FloatRect& crop = outputLayerState.sourceCrop;
-    StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right,
+    StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right,
                   crop.bottom);
+    if (layerState.frameRate.rate != 0 ||
+        layerState.frameRate.type != FrameRateCompatibility::Default) {
+        StringAppendF(&result, "% 6.2ffps %15s\n", layerState.frameRate.rate,
+                      frameRateCompatibilityString(layerState.frameRate.type).c_str());
+    } else {
+        StringAppendF(&result, "\n");
+    }
 
-    result.append("- - - - - - - - - - - - - - - -");
-    result.append("- - - - - - - - - - - - - - - -");
-    result.append("- - - - - - - - - - - - - - -\n");
+    result.append("- - - - - - - - - - - - - - - - ");
+    result.append("- - - - - - - - - - - - - - - - ");
+    result.append("- - - - - - - - - - - - - - - - ");
+    result.append("- - - - - - - - - - - - - - - - ");
+    result.append("- - -\n");
 }
 
 void Layer::dumpFrameStats(std::string& result) const {
@@ -2176,6 +2201,7 @@
         layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
 
         layerInfo->set_corner_radius(getRoundedCornerState().radius);
+        layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
         LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
         LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
                                                [&]() { return layerInfo->mutable_position(); });
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6636b5e..b630333 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -819,6 +819,7 @@
 
     bool setFrameRate(FrameRate frameRate);
     virtual FrameRate getFrameRateForLayerTree() const;
+    static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility);
 
 protected:
     // constant
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 5009e10..18a2891 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -38,13 +38,7 @@
     // because we don't know where this destructor is called from. It could be
     // called with the mStateLock held, leading to a dead-lock (it actually
     // happens).
-    sp<LambdaMessage> cleanUpListMessage =
-            new LambdaMessage([flinger = mFlinger, asBinder = wp<IBinder>(onAsBinder())]() {
-                Mutex::Autolock lock(flinger->mStateLock);
-                flinger->mGraphicBufferProducerList.erase(asBinder);
-            });
-
-    mFlinger->postMessageAsync(cleanUpListMessage);
+    mFlinger->removeGraphicBufferProducerAsync(onAsBinder());
 }
 
 status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
diff --git a/services/surfaceflinger/Promise.h b/services/surfaceflinger/Promise.h
new file mode 100644
index 0000000..a80d441
--- /dev/null
+++ b/services/surfaceflinger/Promise.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <future>
+#include <type_traits>
+#include <utility>
+
+namespace android::promise {
+namespace impl {
+
+template <typename T>
+struct FutureResult {
+    using Type = T;
+};
+
+template <typename T>
+struct FutureResult<std::future<T>> {
+    using Type = T;
+};
+
+} // namespace impl
+
+template <typename T>
+using FutureResult = typename impl::FutureResult<T>::Type;
+
+template <typename... Args>
+inline auto defer(Args... args) {
+    return std::async(std::launch::deferred, std::forward<Args>(args)...);
+}
+
+template <typename T>
+inline std::future<T> yield(T&& v) {
+    return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
+}
+
+template <typename T>
+struct Chain {
+    Chain(std::future<T>&& f) : future(std::move(f)) {}
+    operator std::future<T>&&() && { return std::move(future); }
+
+    T get() && { return future.get(); }
+
+    template <typename F, typename R = std::invoke_result_t<F, T>>
+    auto then(F&& op) && -> Chain<FutureResult<R>> {
+        return defer(
+                [](auto&& f, F&& op) {
+                    R r = op(f.get());
+                    if constexpr (std::is_same_v<R, FutureResult<R>>) {
+                        return r;
+                    } else {
+                        return r.get();
+                    }
+                },
+                std::move(future), std::forward<F>(op));
+    }
+
+    std::future<T> future;
+};
+
+template <typename T>
+inline Chain<T> chain(std::future<T>&& f) {
+    return std::move(f);
+}
+
+} // namespace android::promise
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 0a0f2f1..2e7fbc1 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -116,9 +116,13 @@
 
     sp<GraphicBuffer> buffer =
             new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
-                              GRALLOC_USAGE_SW_WRITE_RARELY, "RefreshRateOverlayBuffer");
+                              GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
+                                      GRALLOC_USAGE_HW_TEXTURE,
+                              "RefreshRateOverlayBuffer");
     uint8_t* pixels;
     buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+    // Clear buffer content
+    drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
     int left = 0;
     if (hundreds != 0) {
         drawDigit(hundreds, left, color, buffer, pixels);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 68cd84f..27353d8 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -130,7 +130,7 @@
         mVsyncListening = false;
     }
 
-    void onDispSyncEvent(nsecs_t /* when */) final {
+    void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) final {
         std::unique_lock<decltype(mMutex)> lock(mMutex);
 
         if (mPhaseIntervalSetting == Phase::ZERO) {
@@ -199,13 +199,8 @@
     }
 }
 
-void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+void RegionSamplingThread::addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                                        const sp<IRegionSamplingListener>& listener) {
-    wp<Layer> stopLayer;
-    if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) {
-        stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner;
-    }
-
     sp<IBinder> asBinder = IInterface::asBinder(listener);
     asBinder->linkToDeath(this);
     std::lock_guard lock(mSamplingMutex);
@@ -430,7 +425,8 @@
     }
 
     bool ignored;
-    mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false, ignored);
+    mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false /* identityTransform */,
+                                 true /* regionSampling */, ignored);
 
     std::vector<Descriptor> activeDescriptors;
     for (const auto& descriptor : descriptors) {
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 99c07c2..b9b7a3c 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -69,7 +69,7 @@
 
     // Add a listener to receive luma notifications. The luma reported via listener will
     // report the median luma for the layers under the stopLayerHandle, in the samplingArea region.
-    void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+    void addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                      const sp<IRegionSamplingListener>& listener);
     // Remove the listener to stop receiving median luma notifications.
     void removeListener(const sp<IRegionSamplingListener>& listener);
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index fc6ccae..ff91bf7 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -200,7 +200,8 @@
                     }
                 }
 
-                callbackInvocations = gatherCallbackInvocationsLocked(now);
+                callbackInvocations =
+                        gatherCallbackInvocationsLocked(now, computeNextRefreshLocked(0, now));
             }
 
             if (callbackInvocations.size() > 0) {
@@ -303,6 +304,11 @@
         return BAD_VALUE;
     }
 
+    nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const {
+        Mutex::Autolock lock(mMutex);
+        return computeNextRefreshLocked(periodOffset, now);
+    }
+
 private:
     struct EventListener {
         const char* mName;
@@ -315,6 +321,7 @@
     struct CallbackInvocation {
         DispSync::Callback* mCallback;
         nsecs_t mEventTime;
+        nsecs_t mExpectedVSyncTime;
     };
 
     nsecs_t computeNextEventTimeLocked(nsecs_t now) {
@@ -340,7 +347,8 @@
         return duration < (3 * mPeriod) / 5;
     }
 
-    std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
+    std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now,
+                                                                    nsecs_t expectedVSyncTime) {
         if (mTraceDetailedInfo) ATRACE_CALL();
         ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
 
@@ -361,6 +369,10 @@
                 CallbackInvocation ci;
                 ci.mCallback = eventListener.mCallback;
                 ci.mEventTime = t;
+                ci.mExpectedVSyncTime = expectedVSyncTime;
+                if (eventListener.mPhase < 0) {
+                    ci.mExpectedVSyncTime += mPeriod;
+                }
                 ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName,
                       t - eventListener.mLastEventTime);
                 callbackInvocations.push_back(ci);
@@ -426,10 +438,19 @@
     void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
         if (mTraceDetailedInfo) ATRACE_CALL();
         for (size_t i = 0; i < callbacks.size(); i++) {
-            callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
+            callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime,
+                                                    callbacks[i].mExpectedVSyncTime);
         }
     }
 
+    nsecs_t computeNextRefreshLocked(int periodOffset, nsecs_t now) const {
+        nsecs_t phase = mReferenceTime + mPhase;
+        if (mPeriod == 0) {
+            return 0;
+        }
+        return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
+    }
+
     const char* const mName;
 
     bool mStop;
@@ -444,7 +465,7 @@
 
     std::vector<EventListener> mEventListeners;
 
-    Mutex mMutex;
+    mutable Mutex mMutex;
     Condition mCond;
 
     // Flag to turn on logging in systrace.
@@ -458,7 +479,7 @@
 public:
     ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {}
 
-    virtual void onDispSyncEvent(nsecs_t /*when*/) {
+    virtual void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) {
         mParity = !mParity;
     }
 
@@ -845,7 +866,7 @@
     const uint32_t hwcLatency = 0;
 
     // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
-    return computeNextRefresh(hwcLatency, now);
+    return mThread->computeNextRefresh(hwcLatency, now);
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 2faa81c..832f08e 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -36,7 +36,7 @@
     public:
         Callback() = default;
         virtual ~Callback();
-        virtual void onDispSyncEvent(nsecs_t when) = 0;
+        virtual void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0;
 
     protected:
         Callback(Callback const&) = delete;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 4e3f85f..8752b66 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -92,7 +92,7 @@
     }
 }
 
-void DispSyncSource::onDispSyncEvent(nsecs_t when) {
+void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
     VSyncSource::Callback* callback;
     {
         std::lock_guard lock(mCallbackMutex);
@@ -104,7 +104,7 @@
     }
 
     if (callback != nullptr) {
-        callback->onVSyncEvent(when);
+        callback->onVSyncEvent(when, expectedVSyncTimestamp);
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index f278712..2aee3f6 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -40,7 +40,7 @@
 
 private:
     // The following method is the implementation of the DispSync::Callback.
-    virtual void onDispSyncEvent(nsecs_t when);
+    void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
 
     const char* const mName;
     TracedOrdinal<int> mValue;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 8347650..5dedb6a 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -79,8 +79,9 @@
                                 event.hotplug.connected ? "connected" : "disconnected");
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
             return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
-                                ", count=%u}",
-                                event.header.displayId, event.vsync.count);
+                                ", count=%u, expectedVSyncTimestamp=%" PRId64 "}",
+                                event.header.displayId, event.vsync.count,
+                                event.vsync.expectedVSyncTimestamp);
         case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
             return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
                                 ", configId=%u}",
@@ -99,10 +100,11 @@
 }
 
 DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
-                                      uint32_t count) {
+                                      uint32_t count, nsecs_t expectedVSyncTimestamp) {
     DisplayEventReceiver::Event event;
     event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
     event.vsync.count = count;
+    event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp;
     return event;
 }
 
@@ -312,11 +314,12 @@
     mCondition.notify_all();
 }
 
-void EventThread::onVSyncEvent(nsecs_t timestamp) {
+void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) {
     std::lock_guard<std::mutex> lock(mMutex);
 
     LOG_FATAL_IF(!mVSyncState);
-    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count));
+    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
+                                       expectedVSyncTimestamp));
     mCondition.notify_all();
 }
 
@@ -423,7 +426,8 @@
         } else {
             // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
             // display is off, keep feeding clients at 60 Hz.
-            const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms;
+            const std::chrono::nanoseconds timeout =
+                    mState == State::SyntheticVSync ? 16ms : 1000ms;
             if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                 if (mState == State::VSync) {
                     ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
@@ -439,9 +443,10 @@
                 }
 
                 LOG_FATAL_IF(!mVSyncState);
-                mPendingEvents.push_back(makeVSync(mVSyncState->displayId,
-                                                   systemTime(SYSTEM_TIME_MONOTONIC),
-                                                   ++mVSyncState->count));
+                const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
+                const auto expectedVSyncTime = now + timeout.count();
+                mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
+                                                   ++mVSyncState->count, expectedVSyncTime));
             }
         }
     }
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 98b1876..9e7086e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -57,7 +57,7 @@
     class Callback {
     public:
         virtual ~Callback() {}
-        virtual void onVSyncEvent(nsecs_t when) = 0;
+        virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0;
     };
 
     virtual ~VSyncSource() {}
@@ -189,7 +189,7 @@
             REQUIRES(mMutex);
 
     // Implements VSyncSource::Callback
-    void onVSyncEvent(nsecs_t timestamp) override;
+    void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) override;
 
     const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
 
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 31da588..975c9db 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -35,10 +35,10 @@
         mCallback = callback;
     }
 
-    void onInjectSyncEvent(nsecs_t when) {
+    void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
         if (mCallback) {
-            mCallback->onVSyncEvent(when);
+            mCallback->onVSyncEvent(when, expectedVSyncTimestamp);
         }
     }
 
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index d8a666a..6067e69 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -18,10 +18,6 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 
-#include <errno.h>
-#include <stdint.h>
-#include <sys/types.h>
-
 #include <binder/IPCThreadState.h>
 
 #include <utils/Log.h>
@@ -35,26 +31,7 @@
 #include "MessageQueue.h"
 #include "SurfaceFlinger.h"
 
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MessageBase::MessageBase() : MessageHandler() {}
-
-MessageBase::~MessageBase() {}
-
-void MessageBase::handleMessage(const Message&) {
-    this->handler();
-    barrier.open();
-};
-
-// ---------------------------------------------------------------------------
-
-MessageQueue::~MessageQueue() = default;
-
-// ---------------------------------------------------------------------------
-
-namespace impl {
+namespace android::impl {
 
 void MessageQueue::Handler::dispatchRefresh() {
     if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
@@ -62,9 +39,9 @@
     }
 }
 
-void MessageQueue::Handler::dispatchInvalidate(nsecs_t timestamp) {
+void MessageQueue::Handler::dispatchInvalidate(nsecs_t expectedVSyncTimestamp) {
     if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
-        mLastVsyncTime = timestamp;
+        mExpectedVSyncTime = expectedVSyncTimestamp;
         mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
     }
 }
@@ -73,11 +50,11 @@
     switch (message.what) {
         case INVALIDATE:
             android_atomic_and(~eventMaskInvalidate, &mEventMask);
-            mQueue.mFlinger->onMessageReceived(message.what, mLastVsyncTime);
+            mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
             break;
         case REFRESH:
             android_atomic_and(~eventMaskRefresh, &mEventMask);
-            mQueue.mFlinger->onMessageReceived(message.what, mLastVsyncTime);
+            mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
             break;
     }
 }
@@ -123,14 +100,8 @@
     } while (true);
 }
 
-status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
-    const Message dummyMessage;
-    if (relTime > 0) {
-        mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
-    } else {
-        mLooper->sendMessage(messageHandler, dummyMessage);
-    }
-    return NO_ERROR;
+void MessageQueue::postMessage(sp<MessageHandler>&& handler) {
+    mLooper->sendMessage(handler, Message());
 }
 
 void MessageQueue::invalidate() {
@@ -152,7 +123,7 @@
     while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
         for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-                mHandler->dispatchInvalidate(buffer[i].header.timestamp);
+                mHandler->dispatchInvalidate(buffer[i].vsync.expectedVSyncTimestamp);
                 break;
             }
         }
@@ -160,10 +131,7 @@
     return 1;
 }
 
-// ---------------------------------------------------------------------------
-
-} // namespace impl
-} // namespace android
+} // namespace android::impl
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index dbd5e96..132b416 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MESSAGE_QUEUE_H
-#define ANDROID_MESSAGE_QUEUE_H
+#pragma once
 
-#include <errno.h>
-#include <stdint.h>
-#include <sys/types.h>
+#include <cstdint>
+#include <future>
+#include <type_traits>
+#include <utility>
 
 #include <utils/Looper.h>
 #include <utils/Timers.h>
@@ -28,52 +28,30 @@
 #include <gui/IDisplayEventConnection.h>
 #include <private/gui/BitTube.h>
 
-#include "Barrier.h"
 #include "EventThread.h"
 
-#include <functional>
-
 namespace android {
 
 class SurfaceFlinger;
 
-// ---------------------------------------------------------------------------
+template <typename F>
+class Task : public MessageHandler {
+    template <typename G>
+    friend auto makeTask(G&&);
 
-class MessageBase : public MessageHandler {
-public:
-    MessageBase();
+    explicit Task(F&& f) : mTask(std::move(f)) {}
 
-    // return true if message has a handler
-    virtual bool handler() = 0;
+    void handleMessage(const Message&) override { mTask(); }
 
-    // waits for the handler to be processed
-    void wait() const { barrier.wait(); }
-
-protected:
-    virtual ~MessageBase();
-
-private:
-    virtual void handleMessage(const Message& message);
-
-    mutable Barrier barrier;
+    using T = std::invoke_result_t<F>;
+    std::packaged_task<T()> mTask;
 };
 
-class LambdaMessage : public MessageBase {
-public:
-    explicit LambdaMessage(std::function<void()> handler)
-          : MessageBase(), mHandler(std::move(handler)) {}
-
-    bool handler() override {
-        mHandler();
-        // This return value is no longer checked, so it's always safe to return true
-        return true;
-    }
-
-private:
-    const std::function<void()> mHandler;
-};
-
-// ---------------------------------------------------------------------------
+template <typename F>
+inline auto makeTask(F&& f) {
+    sp<Task<F>> task = new Task<F>(std::move(f));
+    return std::make_pair(task, task->mTask.get_future());
+}
 
 class MessageQueue {
 public:
@@ -82,12 +60,12 @@
         REFRESH = 1,
     };
 
-    virtual ~MessageQueue();
+    virtual ~MessageQueue() = default;
 
     virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
     virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
     virtual void waitMessage() = 0;
-    virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
+    virtual void postMessage(sp<MessageHandler>&&) = 0;
     virtual void invalidate() = 0;
     virtual void refresh() = 0;
 };
@@ -101,13 +79,13 @@
         enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
         MessageQueue& mQueue;
         int32_t mEventMask;
-        std::atomic<nsecs_t> mLastVsyncTime;
+        std::atomic<nsecs_t> mExpectedVSyncTime;
 
     public:
         explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
         virtual void handleMessage(const Message& message);
         void dispatchRefresh();
-        void dispatchInvalidate(nsecs_t timestamp);
+        void dispatchInvalidate(nsecs_t expectedVSyncTimestamp);
     };
 
     friend class Handler;
@@ -127,7 +105,7 @@
     void setEventConnection(const sp<EventThreadConnection>& connection) override;
 
     void waitMessage() override;
-    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override;
+    void postMessage(sp<MessageHandler>&&) override;
 
     // sends INVALIDATE message at next VSYNC
     void invalidate() override;
@@ -136,9 +114,5 @@
     void refresh() override;
 };
 
-// ---------------------------------------------------------------------------
-
 } // namespace impl
 } // namespace android
-
-#endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index d9aaa05..fe2e406 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -60,6 +60,12 @@
 PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
       : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
                      refreshRateConfigs.getCurrentRefreshRate().getFps(),
+                     sysprop::vsync_event_phase_offset_ns(1000000),
+                     sysprop::vsync_sf_event_phase_offset_ns(1000000),
+                     getProperty("debug.sf.early_phase_offset_ns"),
+                     getProperty("debug.sf.early_gl_phase_offset_ns"),
+                     getProperty("debug.sf.early_app_phase_offset_ns"),
+                     getProperty("debug.sf.early_gl_app_phase_offset_ns"),
                      // Below defines the threshold when an offset is considered to be negative,
                      // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
                      // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
@@ -69,8 +75,18 @@
                              .value_or(std::numeric_limits<nsecs_t>::max())) {}
 
 PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
-                           nsecs_t thresholdForNextVsync)
-      : mThresholdForNextVsync(thresholdForNextVsync),
+                           nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
+                           std::optional<nsecs_t> earlySfOffsetNs,
+                           std::optional<nsecs_t> earlyGlSfOffsetNs,
+                           std::optional<nsecs_t> earlyAppOffsetNs,
+                           std::optional<nsecs_t> earlyGlAppOffsetNs, nsecs_t thresholdForNextVsync)
+      : mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
+        mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
+        mEarlySfOffsetNs(earlySfOffsetNs),
+        mEarlyGlSfOffsetNs(earlyGlSfOffsetNs),
+        mEarlyAppOffsetNs(earlyAppOffsetNs),
+        mEarlyGlAppOffsetNs(earlyGlAppOffsetNs),
+        mThresholdForNextVsync(thresholdForNextVsync),
         mOffsets(initializeOffsets(refreshRates)),
         mRefreshRateFps(currentFps) {}
 
@@ -106,35 +122,27 @@
 }
 
 PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
-    const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
-    const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
-
-    const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
-    const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
-    const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
-    const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
-
     return {
             {
-                    earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
-                            ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
-                            : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
+                    mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+                            ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
+                            : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
 
-                    earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
+                    mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
             },
             {
-                    earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
-                            ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
-                            : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
+                    mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+                            ? mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
+                            : mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
 
-                    earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
+                    mEarlyGlAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
             },
             {
-                    sfVsyncPhaseOffsetNs < mThresholdForNextVsync
-                            ? sfVsyncPhaseOffsetNs
-                            : sfVsyncPhaseOffsetNs - vsyncDuration,
+                    mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
+                            ? mSfVSyncPhaseOffsetNs
+                            : mSfVSyncPhaseOffsetNs - vsyncDuration,
 
-                    vsyncPhaseOffsetNs,
+                    mVSyncPhaseOffsetNs,
             },
     };
 }
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index fa8011d..9ec6d56 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -69,6 +69,9 @@
 protected:
     // Used for unit tests
     PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
+                 nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
+                 std::optional<nsecs_t> earlySfOffsetNs, std::optional<nsecs_t> earlyGlSfOffsetNs,
+                 std::optional<nsecs_t> earlyAppOffsetNs, std::optional<nsecs_t> earlyGlAppOffsetNs,
                  nsecs_t thresholdForNextVsync);
     std::unordered_map<float, Offsets> initializeOffsets(
             const std::vector<float>& refreshRates) const;
@@ -76,6 +79,12 @@
     Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const;
     Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const;
 
+    const nsecs_t mVSyncPhaseOffsetNs;
+    const nsecs_t mSfVSyncPhaseOffsetNs;
+    const std::optional<nsecs_t> mEarlySfOffsetNs;
+    const std::optional<nsecs_t> mEarlyGlSfOffsetNs;
+    const std::optional<nsecs_t> mEarlyAppOffsetNs;
+    const std::optional<nsecs_t> mEarlyGlAppOffsetNs;
     const nsecs_t mThresholdForNextVsync;
     const std::unordered_map<float, Offsets> mOffsets;
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 5634adb..8d958df 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -58,7 +58,7 @@
     ATRACE_INT("ContentFPS", contentFramerate);
 
     // Find the appropriate refresh rate with minimal error
-    auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
+    auto iter = min_element(mPrimaryRefreshRates.cbegin(), mPrimaryRefreshRates.cend(),
                             [contentFramerate](const auto& lhs, const auto& rhs) -> bool {
                                 return std::abs(lhs->fps - contentFramerate) <
                                         std::abs(rhs->fps - contentFramerate);
@@ -71,7 +71,7 @@
     constexpr float MARGIN = 0.05f;
     float ratio = (*iter)->fps / contentFramerate;
     if (std::abs(std::round(ratio) - ratio) > MARGIN) {
-        while (iter != mAvailableRefreshRates.cend()) {
+        while (iter != mPrimaryRefreshRates.cend()) {
             ratio = (*iter)->fps / contentFramerate;
 
             if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
@@ -97,8 +97,8 @@
     return {displayFramesQuot, displayFramesRem};
 }
 
-const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
-        const std::vector<LayerRequirement>& layers, bool touchActive,
+const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
+        const std::vector<LayerRequirement>& layers, bool touchActive, bool idle,
         bool* touchConsidered) const {
     ATRACE_CALL();
     ALOGV("getRefreshRateForContent %zu layers", layers.size());
@@ -106,13 +106,6 @@
     *touchConsidered = false;
     std::lock_guard lock(mLock);
 
-    // If there are not layers, there is not content detection, so return the current
-    // refresh rate.
-    if (layers.empty()) {
-        *touchConsidered = touchActive;
-        return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
-    }
-
     int noVoteLayers = 0;
     int minVoteLayers = 0;
     int maxVoteLayers = 0;
@@ -135,25 +128,33 @@
         }
     }
 
-    // Consider the touch event if there are no ExplicitDefault layers.
-    // ExplicitDefault are mostly interactive (as opposed to ExplicitExactOrMultiple)
-    // and therefore if those posted an explicit vote we should not change it
-    // if get get a touch event.
-    if (touchActive && explicitDefaultVoteLayers == 0) {
+    // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
+    // selected a refresh rate to see if we should apply touch boost.
+    if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
         *touchConsidered = true;
-        return *mAvailableRefreshRates.back();
+        return getMaxRefreshRateByPolicyLocked();
+    }
+
+    if (!touchActive && idle) {
+        return getMinRefreshRateByPolicyLocked();
+    }
+
+    if (layers.empty()) {
+        return getCurrentRefreshRateByPolicyLocked();
     }
 
     // Only if all layers want Min we should return Min
     if (noVoteLayers + minVoteLayers == layers.size()) {
-        return *mAvailableRefreshRates.front();
+        return getMinRefreshRateByPolicyLocked();
     }
 
+    const Policy* policy = getCurrentPolicyLocked();
+
     // Find the best refresh rate based on score
     std::vector<std::pair<const RefreshRate*, float>> scores;
-    scores.reserve(mAvailableRefreshRates.size());
+    scores.reserve(mAppRequestRefreshRates.size());
 
-    for (const auto refreshRate : mAvailableRefreshRates) {
+    for (const auto refreshRate : mAppRequestRefreshRates) {
         scores.emplace_back(refreshRate, 0.0f);
     }
 
@@ -166,6 +167,15 @@
         auto weight = layer.weight;
 
         for (auto i = 0u; i < scores.size(); i++) {
+            bool inPrimaryRange =
+                    scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
+            if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+                layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
+                // Only layers with explicit frame rate settings are allowed to score refresh rates
+                // outside the primary range.
+                continue;
+            }
+
             // If the layer wants Max, give higher score to the higher refresh rate
             if (layer.vote == LayerVoteType::Max) {
                 const auto ratio = scores[i].first->fps / scores.back().first->fps;
@@ -249,6 +259,17 @@
             ? getBestRefreshRate(scores.rbegin(), scores.rend())
             : getBestRefreshRate(scores.begin(), scores.end());
 
+    // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
+    // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
+    // vote we should not change it if we get a touch event. Only apply touch boost if it will
+    // actually increase the refresh rate over the normal selection.
+    const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+    if (touchActive && explicitDefaultVoteLayers == 0 &&
+        bestRefreshRate->fps < touchRefreshRate.fps) {
+        *touchConsidered = true;
+        return touchRefreshRate;
+    }
+
     return *bestRefreshRate;
 }
 
@@ -278,12 +299,20 @@
 
 const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
     std::lock_guard lock(mLock);
-    return *mAvailableRefreshRates.front();
+    return getMinRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+    return *mPrimaryRefreshRates.front();
 }
 
 const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
     std::lock_guard lock(mLock);
-        return *mAvailableRefreshRates.back();
+    return getMaxRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+    return *mPrimaryRefreshRates.back();
 }
 
 const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -297,8 +326,8 @@
 }
 
 const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
-    if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
-                  mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
+    if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
+                  mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
         return *mCurrentRefreshRate;
     }
     return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
@@ -320,7 +349,7 @@
         const float fps = 1e9f / config->getVsyncPeriod();
         mRefreshRates.emplace(configId,
                               std::make_unique<RefreshRate>(configId, config,
-                                                            base::StringPrintf("%2.ffps", fps), fps,
+                                                            base::StringPrintf("%.0ffps", fps), fps,
                                                             RefreshRate::ConstructorTag(0)));
         if (configId == currentConfigId) {
             mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -342,10 +371,11 @@
         return false;
     }
     const RefreshRate& refreshRate = *iter->second;
-    if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) {
+    if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
         return false;
     }
-    return true;
+    return policy.appRequestRange.min <= policy.primaryRange.min &&
+            policy.appRequestRange.max >= policy.primaryRange.max;
 }
 
 status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -392,7 +422,7 @@
 
 bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
     std::lock_guard lock(mLock);
-    for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
+    for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
         if (refreshRate->configId == config) {
             return true;
         }
@@ -430,33 +460,44 @@
     // Filter configs based on current policy and sort based on vsync period
     const Policy* policy = getCurrentPolicyLocked();
     const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
-    ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
-          policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->minRefreshRate,
-          policy->maxRefreshRate);
-    getSortedRefreshRateList(
-            [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
-                const auto& hwcConfig = refreshRate.hwcConfig;
+    ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
+          " appRequestRange=[%.2f %.2f]",
+          policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
+          policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
 
-                return hwcConfig->getHeight() == defaultConfig->getHeight() &&
-                        hwcConfig->getWidth() == defaultConfig->getWidth() &&
-                        hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
-                        hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
-                        (policy->allowGroupSwitching ||
-                         hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
-                        refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate);
-            },
-            &mAvailableRefreshRates);
+    auto filterRefreshRates = [&](float min, float max, const char* listName,
+                                  std::vector<const RefreshRate*>* outRefreshRates) {
+        getSortedRefreshRateList(
+                [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
+                    const auto& hwcConfig = refreshRate.hwcConfig;
 
-    std::string availableRefreshRates;
-    for (const auto& refreshRate : mAvailableRefreshRates) {
-        base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
-    }
+                    return hwcConfig->getHeight() == defaultConfig->getHeight() &&
+                            hwcConfig->getWidth() == defaultConfig->getWidth() &&
+                            hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
+                            hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
+                            (policy->allowGroupSwitching ||
+                             hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
+                            refreshRate.inPolicy(min, max);
+                },
+                outRefreshRates);
 
-    ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
-    LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
-                        "No compatible display configs for default=%d min=%.0f max=%.0f",
-                        policy->defaultConfig.value(), policy->minRefreshRate,
-                        policy->maxRefreshRate);
+        LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
+                            "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
+                            max);
+        auto stringifyRefreshRates = [&]() -> std::string {
+            std::string str;
+            for (auto refreshRate : *outRefreshRates) {
+                base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
+            }
+            return str;
+        };
+        ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
+    };
+
+    filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
+                       &mPrimaryRefreshRates);
+    filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
+                       &mAppRequestRefreshRates);
 }
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index dea7e90..2657dee 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -107,18 +107,46 @@
             std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
 
     struct Policy {
+        struct Range {
+            float min = 0;
+            float max = std::numeric_limits<float>::max();
+
+            bool operator==(const Range& other) const {
+                return min == other.min && max == other.max;
+            }
+
+            bool operator!=(const Range& other) const { return !(*this == other); }
+        };
+
         // The default config, used to ensure we only initiate display config switches within the
         // same config group as defaultConfigId's group.
         HwcConfigIndexType defaultConfig;
-        // The min and max FPS allowed by the policy.
-        float minRefreshRate = 0;
-        float maxRefreshRate = std::numeric_limits<float>::max();
+        // The primary refresh rate range represents display manager's general guidance on the
+        // display configs we'll consider when switching refresh rates. Unless we get an explicit
+        // signal from an app, we should stay within this range.
+        Range primaryRange;
+        // The app request refresh rate range allows us to consider more display configs when
+        // switching refresh rates. Although we should generally stay within the primary range,
+        // specific considerations, such as layer frame rate settings specified via the
+        // setFrameRate() api, may cause us to go outside the primary range. We never go outside the
+        // app request range. The app request range will be greater than or equal to the primary
+        // refresh rate range, never smaller.
+        Range appRequestRange;
         // Whether or not we switch config groups to get the best frame rate. Only used by tests.
         bool allowGroupSwitching = false;
 
+        Policy() = default;
+        Policy(HwcConfigIndexType defaultConfig, const Range& range)
+              : Policy(defaultConfig, range, range) {}
+        Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
+               const Range& appRequestRange)
+              : defaultConfig(defaultConfig),
+                primaryRange(primaryRange),
+                appRequestRange(appRequestRange) {}
+
         bool operator==(const Policy& other) const {
-            return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate &&
-                    maxRefreshRate == other.maxRefreshRate &&
+            return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange &&
+                    appRequestRange == other.appRequestRange &&
                     allowGroupSwitching == other.allowGroupSwitching;
         }
 
@@ -184,12 +212,14 @@
     const RefreshRate& getRefreshRateForContent(const std::vector<LayerRequirement>& layers) const
             EXCLUDES(mLock);
 
-    // Returns the refresh rate that fits best to the given layers. This function also gets a
-    // boolean flag that indicates whether user touched the screen recently to be factored in when
-    // choosing the refresh rate and returns whether the refresh rate was chosen as a result of
-    // a touch event.
-    const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers,
-                                                  bool touchActive, bool* touchConsidered) const
+    // Returns the refresh rate that fits best to the given layers.
+    //   layers - The layer requirements to consider.
+    //   touchActive - Whether the user touched the screen recently. Used to apply touch boost.
+    //   idle - True if the system hasn't seen any buffers posted to layers recently.
+    //   touchConsidered - An output param that tells the caller whether the refresh rate was chosen
+    //                     based on touch boost.
+    const RefreshRate& getBestRefreshRate(const std::vector<LayerRequirement>& layers,
+                                          bool touchActive, bool idle, bool* touchConsidered) const
             EXCLUDES(mLock);
 
     // Returns all the refresh rates supported by the device. This won't change at runtime.
@@ -198,13 +228,15 @@
     // Returns the lowest refresh rate supported by the device. This won't change at runtime.
     const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; }
 
-    // Returns the lowest refresh rate according to the current policy. May change in runtime.
+    // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+    // uses the primary range, not the app request range.
     const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock);
 
     // Returns the highest refresh rate supported by the device. This won't change at runtime.
     const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; }
 
-    // Returns the highest refresh rate according to the current policy. May change in runtime.
+    // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+    // uses the primary range, not the app request range.
     const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
 
     // Returns the current refresh rate
@@ -243,6 +275,14 @@
     // display refresh period.
     std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const;
 
+    // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+    // uses the primary range, not the app request range.
+    const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
+    // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+    // uses the primary range, not the app request range.
+    const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
     // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
     // the policy.
     const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
@@ -254,9 +294,13 @@
     // object is initialized.
     AllRefreshRatesMapType mRefreshRates;
 
-    // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod
-    // (the first element is the lowest refresh rate)
-    std::vector<const RefreshRate*> mAvailableRefreshRates GUARDED_BY(mLock);
+    // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod
+    // (the first element is the lowest refresh rate).
+    std::vector<const RefreshRate*> mPrimaryRefreshRates GUARDED_BY(mLock);
+
+    // The list of refresh rates in the app request range of the current policy, ordered by
+    // vsyncPeriod (the first element is the lowest refresh rate).
+    std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock);
 
     // The current config. This will change at runtime. This is set by SurfaceFlinger on
     // the main thread, and read by the Scheduler (and other objects) on other threads.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 66d4a03..d9e7b37 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,14 +41,15 @@
 
 public:
     RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats,
-                     HwcConfigIndexType currentConfigId, int currentPowerMode)
+                     HwcConfigIndexType currentConfigId,
+                     android::hardware::graphics::composer::hal::PowerMode currentPowerMode)
           : mRefreshRateConfigs(refreshRateConfigs),
             mTimeStats(timeStats),
             mCurrentConfigMode(currentConfigId),
             mCurrentPowerMode(currentPowerMode) {}
 
     // Sets power mode.
-    void setPowerMode(int mode) {
+    void setPowerMode(android::hardware::graphics::composer::hal::PowerMode mode) {
         if (mCurrentPowerMode == mode) {
             return;
         }
@@ -108,7 +109,7 @@
         mPreviousRecordedTime = currentTime;
 
         uint32_t fps = 0;
-        if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
+        if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) {
             // Normal power mode is counted under different config modes.
             if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) {
                 mConfigModesTotalTime[mCurrentConfigMode] = 0;
@@ -140,7 +141,7 @@
     TimeStats& mTimeStats;
 
     HwcConfigIndexType mCurrentConfigMode;
-    int32_t mCurrentPowerMode;
+    android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode;
 
     std::unordered_map<HwcConfigIndexType /* configId */, int64_t /* duration in ms */>
             mConfigModesTotalTime;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3a84b67..d73fd8b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -276,12 +276,12 @@
     return mInjectorConnectionHandle;
 }
 
-bool Scheduler::injectVSync(nsecs_t when) {
+bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime) {
     if (!mInjectVSyncs || !mVSyncInjector) {
         return false;
     }
 
-    mVSyncInjector->onInjectSyncEvent(when);
+    mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime);
     return true;
 }
 
@@ -469,7 +469,7 @@
     // that is currently on top. b/142507166 will give us this capability.
     std::lock_guard<std::mutex> lock(mFeatureStateLock);
     if (mLayerHistory) {
-        // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2
+        // Layer History will be cleared based on RefreshRateConfigs::getBestRefreshRate
 
         mTouchTimer->reset();
 
@@ -574,29 +574,28 @@
 HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
     ATRACE_CALL();
 
-    // NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
-    // code will have to be refactored. 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 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 (mDisplayPowerTimer &&
         (!mFeatures.isDisplayPowerStateNormal ||
          mFeatures.displayPowerTimer == TimerState::Reset)) {
         return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId();
     }
 
+    const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
+    const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;
+
     if (!mUseContentDetectionV2) {
         // As long as touch is active we want to be in performance mode.
-        if (mTouchTimer && mFeatures.touch == TouchState::Active) {
+        if (touchActive) {
             return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId();
         }
-    }
 
-    // If timer has expired as it means there is no new content on the screen.
-    if (mIdleTimer && mFeatures.idleTimer == TimerState::Expired) {
-        return mRefreshRateConfigs.getMinRefreshRateByPolicy().getConfigId();
-    }
+        // If timer has expired as it means there is no new content on the screen.
+        if (idle) {
+            return mRefreshRateConfigs.getMinRefreshRateByPolicy().getConfigId();
+        }
 
-    if (!mUseContentDetectionV2) {
         // If content detection is off we choose performance as we don't know the content fps.
         if (mFeatures.contentDetectionV1 == ContentDetectionState::Off) {
             // NOTE: V1 always calls this, but this is not a default behavior for V2.
@@ -609,13 +608,10 @@
     }
 
     bool touchConsidered;
-    const auto& ret =
-            mRefreshRateConfigs
-                    .getRefreshRateForContentV2(mFeatures.contentRequirements,
-                                                mTouchTimer &&
-                                                        mFeatures.touch == TouchState::Active,
-                                                &touchConsidered)
-                    .getConfigId();
+    const auto& ret = mRefreshRateConfigs
+                              .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle,
+                                                  &touchConsidered)
+                              .getConfigId();
     if (touchConsidered) {
         // Clear layer history if refresh rate was selected based on touch to allow
         // the hueristic to pick up with the new rate.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 75c02f3..4a0280f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -95,7 +95,7 @@
     ConnectionHandle enableVSyncInjection(bool enable);
 
     // Returns false if injection is disabled.
-    bool injectVSync(nsecs_t when);
+    bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime);
 
     void enableHardwareVsync();
     void disableHardwareVsync(bool makeUnavailable);
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 2f1faac..5f0c9ce 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -128,7 +128,7 @@
             mLastCallTime = vsynctime;
         }
 
-        mCallback->onDispSyncEvent(wakeupTime);
+        mCallback->onDispSyncEvent(wakeupTime, vsynctime);
 
         {
             std::lock_guard<std::mutex> lk(mMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46da5cc..be2c4e4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -108,6 +108,7 @@
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
+#include "Promise.h"
 #include "RefreshRateOverlay.h"
 #include "RegionSamplingThread.h"
 #include "Scheduler/DispSync.h"
@@ -414,15 +415,13 @@
     useFrameRateApi = use_frame_rate_api(true);
 }
 
-void SurfaceFlinger::onFirstRef()
-{
+SurfaceFlinger::~SurfaceFlinger() = default;
+
+void SurfaceFlinger::onFirstRef() {
     mEventQueue->init(this);
 }
 
-SurfaceFlinger::~SurfaceFlinger() = default;
-
-void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
-{
+void SurfaceFlinger::binderDied(const wp<IBinder>&) {
     // the window manager died on us. prepare its eulogy.
     mBootFinished = false;
 
@@ -433,21 +432,25 @@
     startBootAnim();
 }
 
-static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
-    status_t err = client->initCheck();
-    if (err == NO_ERROR) {
-        return client;
+void SurfaceFlinger::run() {
+    while (true) {
+        mEventQueue->waitMessage();
     }
-    return nullptr;
+}
+
+template <typename F, typename T>
+inline std::future<T> SurfaceFlinger::schedule(F&& f) {
+    auto [task, future] = makeTask(std::move(f));
+    mEventQueue->postMessage(std::move(task));
+    return std::move(future);
 }
 
 sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
-    return initClient(new Client(this));
+    const sp<Client> client = new Client(this);
+    return client->initCheck() == NO_ERROR ? client : nullptr;
 }
 
-sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
-        bool secure)
-{
+sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) {
     class DisplayToken : public BBinder {
         sp<SurfaceFlinger> flinger;
         virtual ~DisplayToken() {
@@ -583,7 +586,7 @@
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 
-    postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
+    static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS {
         readPersistentProperties();
         mPowerAdvisor.onBootFinished();
         mBootStage = BootStage::FINISHED;
@@ -611,9 +614,12 @@
 
     // The pool was empty, so we need to get a new texture name directly using a
     // blocking call to the main thread
-    uint32_t name = 0;
-    postMessageSync(new LambdaMessage([&]() { getRenderEngine().genTextures(1, &name); }));
-    return name;
+    return schedule([this] {
+               uint32_t name = 0;
+               getRenderEngine().genTextures(1, &name);
+               return name;
+           })
+            .get();
 }
 
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -667,7 +673,7 @@
             // mStateLock from the vr flinger dispatch thread might trigger a
             // deadlock in surface flinger (see b/66916578), so post a message
             // to be handled on the main thread instead.
-            postMessageAsync(new LambdaMessage([=] {
+            static_cast<void>(schedule([=] {
                 ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
                 mVrFlingerRequestsDisplay = requestDisplay;
                 signalTransaction();
@@ -989,29 +995,26 @@
         return BAD_VALUE;
     }
 
-    status_t result = NAME_NOT_FOUND;
-
-    postMessageSync(new LambdaMessage([&]() {
+    auto future = schedule([=]() -> status_t {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set allowed display configs for invalid display token %p",
                   displayToken.get());
+            return NAME_NOT_FOUND;
         } else if (display->isVirtual()) {
             ALOGW("Attempt to set allowed display configs for virtual display");
-            result = INVALID_OPERATION;
+            return INVALID_OPERATION;
         } else {
-            HwcConfigIndexType config(mode);
-            const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config);
-            result = setDesiredDisplayConfigSpecsInternal(display,
-                                                          scheduler::RefreshRateConfigs::
-                                                                  Policy{config,
-                                                                         refreshRate.getFps(),
-                                                                         refreshRate.getFps()},
-                                                          /*overridePolicy=*/false);
-        }
-    }));
+            const HwcConfigIndexType config(mode);
+            const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
+            const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
+            constexpr bool kOverridePolicy = false;
 
-    return result;
+            return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
+        }
+    });
+
+    return future.get();
 }
 
 void SurfaceFlinger::setActiveConfigInternal() {
@@ -1185,7 +1188,7 @@
 }
 
 status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
-    postMessageSync(new LambdaMessage([&] {
+    schedule([=] {
         Vector<ColorMode> modes;
         getDisplayColorModes(displayToken, &modes);
         bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
@@ -1207,7 +1210,7 @@
                                                             RenderIntent::COLORIMETRIC,
                                                             Dataspace::UNKNOWN});
         }
-    }));
+    }).wait();
 
     return NO_ERROR;
 }
@@ -1231,7 +1234,7 @@
 }
 
 void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
-    postMessageAsync(new LambdaMessage([=] {
+    static_cast<void>(schedule([=] {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             getHwComposer().setAutoLowLatencyMode(*displayId, on);
         } else {
@@ -1262,7 +1265,7 @@
 }
 
 void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
-    postMessageAsync(new LambdaMessage([=] {
+    static_cast<void>(schedule([=] {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
             getHwComposer().setContentType(*displayId, type);
@@ -1352,18 +1355,17 @@
 status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
                                                           bool enable, uint8_t componentMask,
                                                           uint64_t maxFrames) {
-    status_t result = NAME_NOT_FOUND;
-
-    postMessageSync(new LambdaMessage([&] {
-        if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
-            result = getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
-                                                                      componentMask, maxFrames);
-        } else {
-            ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
-        }
-    }));
-
-    return result;
+    return schedule([=]() -> status_t {
+               if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+                   return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
+                                                                           componentMask,
+                                                                           maxFrames);
+               } else {
+                   ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+                   return NAME_NOT_FOUND;
+               }
+           })
+            .get();
 }
 
 status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
@@ -1405,21 +1407,21 @@
 }
 
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
-    postMessageSync(new LambdaMessage([&] {
+    schedule([=] {
         Mutex::Autolock lock(mStateLock);
 
         if (const auto handle = mScheduler->enableVSyncInjection(enable)) {
             mEventQueue->setEventConnection(
                     mScheduler->getEventConnection(enable ? handle : mSfConnectionHandle));
         }
-    }));
+    }).wait();
 
     return NO_ERROR;
 }
 
 status_t SurfaceFlinger::injectVSync(nsecs_t when) {
     Mutex::Autolock lock(mStateLock);
-    return mScheduler->injectVSync(when) ? NO_ERROR : BAD_VALUE;
+    return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE;
 }
 
 status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
@@ -1458,7 +1460,9 @@
     if (!listener || samplingArea == Rect::INVALID_RECT) {
         return BAD_VALUE;
     }
-    mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
+
+    const wp<Layer> stopLayer = fromHandle(stopLayerHandle);
+    mRegionSamplingThread->addListener(samplingArea, stopLayer, listener);
     return NO_ERROR;
 }
 
@@ -1492,17 +1496,16 @@
         return BAD_VALUE;
     }
 
-    status_t result = NAME_NOT_FOUND;
-
-    postMessageSync(new LambdaMessage([&] {
-        if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
-            result = getHwComposer().setDisplayBrightness(*displayId, brightness);
-        } else {
-            ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
-        }
-    }));
-
-    return result;
+    return promise::chain(schedule([=] {
+               if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+                   return getHwComposer().setDisplayBrightness(*displayId, brightness);
+               } else {
+                   ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+                   return promise::yield<status_t>(NAME_NOT_FOUND);
+               }
+           }))
+            .then([](std::future<status_t> task) { return task; })
+            .get();
 }
 
 status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
@@ -1525,12 +1528,6 @@
     return mScheduler->createDisplayEventConnection(handle, configChanged);
 }
 
-// ----------------------------------------------------------------------------
-
-void SurfaceFlinger::waitForEvent() {
-    mEventQueue->waitMessage();
-}
-
 void SurfaceFlinger::signalTransaction() {
     mScheduler->resetIdleTimer();
     mPowerAdvisor.notifyDisplayUpdateImminent();
@@ -1548,26 +1545,6 @@
     mEventQueue->refresh();
 }
 
-status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t /* flags */) {
-    return mEventQueue->postMessage(msg, reltime);
-}
-
-status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t /* flags */) {
-    status_t res = mEventQueue->postMessage(msg, reltime);
-    if (res == NO_ERROR) {
-        msg->wait();
-    }
-    return res;
-}
-
-void SurfaceFlinger::run() {
-    do {
-        waitForEvent();
-    } while (true);
-}
-
 nsecs_t SurfaceFlinger::getVsyncPeriod() const {
     const auto displayId = getInternalDisplayIdLocked();
     if (!displayId || !getHwComposer().isConnected(*displayId)) {
@@ -1685,8 +1662,8 @@
 
     // Enable / Disable HWVsync from the main thread to avoid race conditions with
     // display power state.
-    postMessageAsync(new LambdaMessage(
-            [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
+    static_cast<void>(
+            schedule([=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
 }
 
 void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
@@ -1735,7 +1712,7 @@
     sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
     LOG_ALWAYS_FATAL_IF(!display);
 
-    const int currentDisplayPowerMode = display->getPowerMode();
+    const hal::PowerMode currentDisplayPowerMode = display->getPowerMode();
 
     // Clear out all the output layers from the composition engine for all
     // displays before destroying the hardware composer interface. This ensures
@@ -1811,11 +1788,10 @@
         return false;
     }
 
-    if (graceTimeMs > 0 && fence->getStatus() == Fence::Status::Unsignaled) {
-        fence->wait(graceTimeMs);
-    }
-
-    return (fence->getStatus() == Fence::Status::Unsignaled);
+    const status_t status = fence->wait(graceTimeMs);
+    // This is the same as Fence::Status::Unsignaled, but it saves a getStatus() call,
+    // which calls wait(0) again internally
+    return status == -ETIME;
 }
 
 nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS {
@@ -1828,197 +1804,201 @@
     return fence->getSignalTime();
 }
 
-void SurfaceFlinger::populateExpectedPresentTime(nsecs_t wakeupTime) {
+nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const {
     DisplayStatInfo stats;
     mScheduler->getDisplayStatInfo(&stats);
-    const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(wakeupTime);
+    const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now);
     // Inflate the expected present time if we're targetting the next vsync.
-    mExpectedPresentTime.store(
-            mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod);
+    return mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod;
 }
 
-void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t when) NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::onMessageReceived(int32_t what,
+                                       nsecs_t expectedVSyncTime) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            const nsecs_t frameStart = systemTime();
-            // calculate the expected present time once and use the cached
-            // value throughout this frame to make sure all layers are
-            // seeing this same value.
-            const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
-            populateExpectedPresentTime(when);
-
-            // When Backpressure propagation is enabled we want to give a small grace period
-            // for the present fence to fire instead of just giving up on this frame to handle cases
-            // where present fence is just about to get signaled.
-            const int graceTimeForPresentFenceMs =
-                    (mPropagateBackpressure &&
-                     (mPropagateBackpressureClientComposition || !mHadClientComposition))
-                    ? 1
-                    : 0;
-
-            // Pending frames may trigger backpressure propagation.
-            const TracedOrdinal<bool> framePending = {"PrevFramePending",
-                                                      previousFramePending(
-                                                              graceTimeForPresentFenceMs)};
-
-            // Frame missed counts for metrics tracking.
-            // A frame is missed if the prior frame is still pending. If no longer pending,
-            // then we still count the frame as missed if the predicted present time
-            // was further in the past than when the fence actually fired.
-
-            // Add some slop to correct for drift. This should generally be
-            // smaller than a typical frame duration, but should not be so small
-            // that it reports reasonable drift as a missed frame.
-            DisplayStatInfo stats;
-            mScheduler->getDisplayStatInfo(&stats);
-            const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
-            const nsecs_t previousPresentTime = previousFramePresentTime();
-            const TracedOrdinal<bool> frameMissed =
-                    {"PrevFrameMissed",
-                     framePending ||
-                             (previousPresentTime >= 0 &&
-                              (lastExpectedPresentTime < previousPresentTime - frameMissedSlop))};
-            const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
-                                                        mHadDeviceComposition && frameMissed};
-            const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
-                                                        mHadClientComposition && frameMissed};
-
-            if (frameMissed) {
-                mFrameMissedCount++;
-                mTimeStats->incrementMissedFrames();
-                if (mMissedFrameJankCount == 0) {
-                    mMissedFrameJankStart = systemTime();
-                }
-                mMissedFrameJankCount++;
-            }
-
-            if (hwcFrameMissed) {
-                mHwcFrameMissedCount++;
-            }
-
-            if (gpuFrameMissed) {
-                mGpuFrameMissedCount++;
-            }
-
-            // If we are in the middle of a config change and the fence hasn't
-            // fired yet just wait for the next invalidate
-            if (mSetActiveConfigPending) {
-                if (framePending) {
-                    mEventQueue->invalidate();
-                    break;
-                }
-
-                // We received the present fence from the HWC, so we assume it successfully updated
-                // the config, hence we update SF.
-                mSetActiveConfigPending = false;
-                setActiveConfigInternal();
-            }
-
-            if (framePending && mPropagateBackpressure) {
-                if ((hwcFrameMissed && !gpuFrameMissed) ||
-                    mPropagateBackpressureClientComposition) {
-                    signalLayerUpdate();
-                    break;
-                }
-            }
-
-            // Our jank window is always at least 100ms since we missed a
-            // frame...
-            static constexpr nsecs_t kMinJankyDuration =
-                    std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
-            // ...but if it's larger than 1s then we missed the trace cutoff.
-            static constexpr nsecs_t kMaxJankyDuration =
-                    std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
-            // If we're in a user build then don't push any atoms
-            if (!mIsUserBuild && mMissedFrameJankCount > 0) {
-                const auto displayDevice = getDefaultDisplayDeviceLocked();
-                // Only report jank when the display is on, as displays in DOZE
-                // power mode may operate at a different frame rate than is
-                // reported in their config, which causes noticeable (but less
-                // severe) jank.
-                if (displayDevice && displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL) {
-                    const nsecs_t currentTime = systemTime();
-                    const nsecs_t jankDuration = currentTime - mMissedFrameJankStart;
-                    if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) {
-                        ATRACE_NAME("Jank detected");
-                        ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount);
-                        const int32_t jankyDurationMillis = jankDuration / (1000 * 1000);
-                        android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
-                                                   jankyDurationMillis, mMissedFrameJankCount);
-                    }
-
-                    // We either reported a jank event or we missed the trace
-                    // window, so clear counters here.
-                    if (jankDuration > kMinJankyDuration) {
-                        mMissedFrameJankCount = 0;
-                        mMissedFrameJankStart = 0;
-                    }
-                }
-            }
-
-            // Now that we're going to make it to the handleMessageTransaction()
-            // call below it's safe to call updateVrFlinger(), which will
-            // potentially trigger a display handoff.
-            updateVrFlinger();
-
-            if (mTracingEnabledChanged) {
-                mTracingEnabled = mTracing.isEnabled();
-                mTracingEnabledChanged = false;
-            }
-
-            bool refreshNeeded;
-            {
-                ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
-
-                refreshNeeded = handleMessageTransaction();
-                refreshNeeded |= handleMessageInvalidate();
-                if (mTracingEnabled) {
-                    mAddCompositionStateToTrace =
-                            mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
-                    if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
-                        mTracing.notifyLocked("visibleRegionsDirty");
-                    }
-                }
-            }
-
-            // Layers need to get updated (in the previous line) before we can use them for
-            // choosing the refresh rate.
-            // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
-            // and may eventually call to ~Layer() if it holds the last reference
-            {
-                Mutex::Autolock _l(mStateLock);
-                mScheduler->chooseRefreshRateForContent();
-            }
-
-            performSetActiveConfig();
-
-            updateCursorAsync();
-            updateInputFlinger();
-
-            refreshNeeded |= mRepaintEverything;
-            if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
-                // Signal a refresh if a transaction modified the window state,
-                // a new buffer was latched, or if HWC has requested a full
-                // repaint
-                if (mFrameStartTime <= 0) {
-                    // We should only use the time of the first invalidate
-                    // message that signals a refresh as the beginning of the
-                    // frame. Otherwise the real frame time will be
-                    // underestimated.
-                    mFrameStartTime = frameStart;
-                }
-                signalRefresh();
-            }
+            onMessageInvalidate(expectedVSyncTime);
             break;
         }
         case MessageQueue::REFRESH: {
-            handleMessageRefresh();
+            onMessageRefresh();
             break;
         }
     }
 }
 
+void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) NO_THREAD_SAFETY_ANALYSIS {
+    ATRACE_CALL();
+
+    const nsecs_t frameStart = systemTime();
+    // calculate the expected present time once and use the cached
+    // value throughout this frame to make sure all layers are
+    // seeing this same value.
+    const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
+    mExpectedPresentTime = expectedVSyncTime;
+
+    // When Backpressure propagation is enabled we want to give a small grace period
+    // for the present fence to fire instead of just giving up on this frame to handle cases
+    // where present fence is just about to get signaled.
+    const int graceTimeForPresentFenceMs =
+            (mPropagateBackpressure &&
+             (mPropagateBackpressureClientComposition || !mHadClientComposition))
+            ? 1
+            : 0;
+
+    // Pending frames may trigger backpressure propagation.
+    const TracedOrdinal<bool> framePending = {"PrevFramePending",
+                                              previousFramePending(graceTimeForPresentFenceMs)};
+
+    // Frame missed counts for metrics tracking.
+    // A frame is missed if the prior frame is still pending. If no longer pending,
+    // then we still count the frame as missed if the predicted present time
+    // was further in the past than when the fence actually fired.
+
+    // Add some slop to correct for drift. This should generally be
+    // smaller than a typical frame duration, but should not be so small
+    // that it reports reasonable drift as a missed frame.
+    DisplayStatInfo stats;
+    mScheduler->getDisplayStatInfo(&stats);
+    const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
+    const nsecs_t previousPresentTime = previousFramePresentTime();
+    const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
+                                             framePending ||
+                                                     (previousPresentTime >= 0 &&
+                                                      (lastExpectedPresentTime <
+                                                       previousPresentTime - frameMissedSlop))};
+    const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
+                                                mHadDeviceComposition && frameMissed};
+    const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
+                                                mHadClientComposition && frameMissed};
+
+    if (frameMissed) {
+        mFrameMissedCount++;
+        mTimeStats->incrementMissedFrames();
+        if (mMissedFrameJankCount == 0) {
+            mMissedFrameJankStart = systemTime();
+        }
+        mMissedFrameJankCount++;
+    }
+
+    if (hwcFrameMissed) {
+        mHwcFrameMissedCount++;
+    }
+
+    if (gpuFrameMissed) {
+        mGpuFrameMissedCount++;
+    }
+
+    // If we are in the middle of a config change and the fence hasn't
+    // fired yet just wait for the next invalidate
+    if (mSetActiveConfigPending) {
+        if (framePending) {
+            mEventQueue->invalidate();
+            return;
+        }
+
+        // We received the present fence from the HWC, so we assume it successfully updated
+        // the config, hence we update SF.
+        mSetActiveConfigPending = false;
+        setActiveConfigInternal();
+    }
+
+    if (framePending && mPropagateBackpressure) {
+        if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
+            signalLayerUpdate();
+            return;
+        }
+    }
+
+    // Our jank window is always at least 100ms since we missed a
+    // frame...
+    static constexpr nsecs_t kMinJankyDuration =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
+    // ...but if it's larger than 1s then we missed the trace cutoff.
+    static constexpr nsecs_t kMaxJankyDuration =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+    // If we're in a user build then don't push any atoms
+    if (!mIsUserBuild && mMissedFrameJankCount > 0) {
+        const auto displayDevice = getDefaultDisplayDeviceLocked();
+        // Only report jank when the display is on, as displays in DOZE
+        // power mode may operate at a different frame rate than is
+        // reported in their config, which causes noticeable (but less
+        // severe) jank.
+        if (displayDevice && displayDevice->getPowerMode() == hal::PowerMode::ON) {
+            const nsecs_t currentTime = systemTime();
+            const nsecs_t jankDuration = currentTime - mMissedFrameJankStart;
+            if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) {
+                ATRACE_NAME("Jank detected");
+                ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount);
+                const int32_t jankyDurationMillis = jankDuration / (1000 * 1000);
+                android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
+                                           jankyDurationMillis, mMissedFrameJankCount);
+            }
+
+            // We either reported a jank event or we missed the trace
+            // window, so clear counters here.
+            if (jankDuration > kMinJankyDuration) {
+                mMissedFrameJankCount = 0;
+                mMissedFrameJankStart = 0;
+            }
+        }
+    }
+
+    // Now that we're going to make it to the handleMessageTransaction()
+    // call below it's safe to call updateVrFlinger(), which will
+    // potentially trigger a display handoff.
+    updateVrFlinger();
+
+    if (mTracingEnabledChanged) {
+        mTracingEnabled = mTracing.isEnabled();
+        mTracingEnabledChanged = false;
+    }
+
+    bool refreshNeeded;
+    {
+        ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
+
+        refreshNeeded = handleMessageTransaction();
+        refreshNeeded |= handleMessageInvalidate();
+        if (mTracingEnabled) {
+            mAddCompositionStateToTrace =
+                    mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
+            if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+                mTracing.notifyLocked("visibleRegionsDirty");
+            }
+        }
+    }
+
+    // Layers need to get updated (in the previous line) before we can use them for
+    // choosing the refresh rate.
+    // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
+    // and may eventually call to ~Layer() if it holds the last reference
+    {
+        Mutex::Autolock _l(mStateLock);
+        mScheduler->chooseRefreshRateForContent();
+    }
+
+    performSetActiveConfig();
+
+    updateCursorAsync();
+    updateInputFlinger();
+
+    refreshNeeded |= mRepaintEverything;
+    if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
+        // Signal a refresh if a transaction modified the window state,
+        // a new buffer was latched, or if HWC has requested a full
+        // repaint
+        if (mFrameStartTime <= 0) {
+            // We should only use the time of the first invalidate
+            // message that signals a refresh as the beginning of the
+            // frame. Otherwise the real frame time will be
+            // underestimated.
+            mFrameStartTime = frameStart;
+        }
+        signalRefresh();
+    }
+}
+
 bool SurfaceFlinger::handleMessageTransaction() {
     ATRACE_CALL();
     uint32_t transactionFlags = peekTransactionFlags();
@@ -2041,7 +2021,7 @@
     return runHandleTransaction;
 }
 
-void SurfaceFlinger::handleMessageRefresh() {
+void SurfaceFlinger::onMessageRefresh() {
     ATRACE_CALL();
 
     mRefreshPending = false;
@@ -2139,7 +2119,6 @@
     }
 }
 
-
 bool SurfaceFlinger::handleMessageInvalidate() {
     ATRACE_CALL();
     bool refreshNeeded = handlePageFlip();
@@ -2272,7 +2251,7 @@
     mTransactionCompletedThread.sendCallbacks();
 
     if (displayDevice && displayDevice->isPrimary() &&
-        displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL && presentFenceTime->isValid()) {
+        displayDevice->getPowerMode() == hal::PowerMode::ON && presentFenceTime->isValid()) {
         mScheduler->addPresentFence(presentFenceTime);
     }
 
@@ -2366,6 +2345,10 @@
     }
 }
 
+FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const {
+    return displayDevice.getViewport().toFloatRect();
+}
+
 void SurfaceFlinger::computeLayerBounds() {
     for (const auto& pair : mDisplays) {
         const auto& displayDevice = pair.second;
@@ -2376,7 +2359,7 @@
                 continue;
             }
 
-            layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform(),
+            layer->computeBounds(getLayerClipBoundsForDisplay(*displayDevice), ui::Transform(),
                                  0.f /* shadowRadius */);
         }
     }
@@ -2538,7 +2521,7 @@
             isInternalDisplay ? internalDisplayOrientation : ui::ROTATION_0;
 
     // virtual displays are always considered enabled
-    creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
+    creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
 
     sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs);
 
@@ -2959,7 +2942,7 @@
                                                             currentConfig);
     mRefreshRateStats =
             std::make_unique<scheduler::RefreshRateStats>(*mRefreshRateConfigs, *mTimeStats,
-                                                          currentConfig, HWC_POWER_MODE_OFF);
+                                                          currentConfig, hal::PowerMode::OFF);
     mRefreshRateStats->setConfigMode(currentConfig);
 
     mPhaseConfiguration = getFactory().createPhaseConfiguration(*mRefreshRateConfigs);
@@ -3164,7 +3147,7 @@
         Mutex::Autolock _l(mStateLock);
         sp<Layer> parent;
         if (parentHandle != nullptr) {
-            parent = fromHandle(parentHandle);
+            parent = fromHandleLocked(parentHandle).promote();
             if (parent == nullptr) {
                 return NAME_NOT_FOUND;
             }
@@ -3213,6 +3196,13 @@
     return NO_ERROR;
 }
 
+void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) {
+    static_cast<void>(schedule([=] {
+        Mutex::Autolock lock(mStateLock);
+        mGraphicBufferProducerList.erase(binder);
+    }));
+}
+
 uint32_t SurfaceFlinger::peekTransactionFlags() {
     return mTransactionFlags;
 }
@@ -3251,7 +3241,6 @@
             while (!transactionQueue.empty()) {
                 const auto& transaction = transactionQueue.front();
                 if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
-                                                   true /* useCachedExpectedPresentTime */,
                                                    transaction.states)) {
                     setTransactionFlags(eTransactionFlushNeeded);
                     break;
@@ -3283,9 +3272,7 @@
 
 
 bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
-                                                   bool useCachedExpectedPresentTime,
                                                    const Vector<ComposerState>& states) {
-    if (!useCachedExpectedPresentTime) populateExpectedPresentTime(systemTime());
 
     const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
     // Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3337,9 +3324,13 @@
         }
     }
 
+    const bool pendingTransactions = itr != mTransactionQueues.end();
     // Expected present time is computed and cached on invalidate, so it may be stale.
-    if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied(
-            desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) {
+    if (!pendingTransactions) {
+        mExpectedPresentTime = calculateExpectedPresentTime(systemTime());
+    }
+
+    if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
                                                uncacheBuffer, postTime, privileged,
                                                hasListenerCallbacks, listenerCallbacks);
@@ -3438,18 +3429,26 @@
                                                   : Scheduler::TransactionStart::NORMAL;
         setTransactionFlags(transactionFlags, start);
 
-        // if this is a synchronous transaction, wait for it to take effect
-        // before returning.
-        if (flags & eSynchronous) {
-            mTransactionPending = true;
-        }
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
         }
-        if (mPendingInputWindowCommands.syncInputWindows) {
+
+        // if this is a synchronous transaction, wait for it to take effect
+        // before returning.
+        const bool synchronous = flags & eSynchronous;
+        const bool syncInput = inputWindowCommands.syncInputWindows;
+        if (!synchronous && !syncInput) {
+            return;
+        }
+
+        if (synchronous) {
+            mTransactionPending = true;
+        }
+        if (syncInput) {
             mPendingSyncInputWindows = true;
         }
 
+
         // applyTransactionState can be called by either the main SF thread or by
         // another process through setTransactionState.  While a given process may wish
         // to wait on synchronous transactions, the main SF thread should never
@@ -3543,7 +3542,7 @@
 
     sp<Layer> layer = nullptr;
     if (s.surface) {
-        layer = fromHandle(s.surface);
+        layer = fromHandleLocked(s.surface).promote();
     } else {
         // The client may provide us a null handle. Treat it as if the layer was removed.
         ALOGW("Attempt to set client state with a null layer handle");
@@ -3859,7 +3858,7 @@
 
     {
         Mutex::Autolock _l(mStateLock);
-        mirrorFrom = fromHandle(mirrorFromHandle);
+        mirrorFrom = fromHandleLocked(mirrorFromHandle).promote();
         if (!mirrorFrom) {
             return NAME_NOT_FOUND;
         }
@@ -4122,7 +4121,7 @@
     setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false,
                         {});
 
-    setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
+    setPowerModeInternal(display, hal::PowerMode::ON);
 
     const nsecs_t vsyncPeriod = getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
@@ -4135,8 +4134,7 @@
 
 void SurfaceFlinger::initializeDisplays() {
     // Async since we may be called from the main thread.
-    postMessageAsync(
-            new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
+    static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
 }
 
 void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled) {
@@ -4146,7 +4144,7 @@
     }
 }
 
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
     if (display->isVirtual()) {
         ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
         return;
@@ -4157,7 +4155,7 @@
 
     ALOGD("Setting power mode %d on display %s", mode, to_string(*displayId).c_str());
 
-    int currentMode = display->getPowerMode();
+    const hal::PowerMode currentMode = display->getPowerMode();
     if (mode == currentMode) {
         return;
     }
@@ -4165,15 +4163,15 @@
     display->setPowerMode(mode);
 
     if (mInterceptor->isEnabled()) {
-        mInterceptor->savePowerModeUpdate(display->getSequenceId(), mode);
+        mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
     }
 
-    if (currentMode == HWC_POWER_MODE_OFF) {
+    if (currentMode == hal::PowerMode::OFF) {
         if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
             ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
         }
         getHwComposer().setPowerMode(*displayId, mode);
-        if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+        if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
             setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
@@ -4182,12 +4180,12 @@
         mVisibleRegionsDirty = true;
         mHasPoweredOff = true;
         repaintEverything();
-    } else if (mode == HWC_POWER_MODE_OFF) {
+    } else if (mode == hal::PowerMode::OFF) {
         // Turn off the display
         if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
             ALOGW("Couldn't set SCHED_OTHER on display off: %s\n", strerror(errno));
         }
-        if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
+        if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->disableHardwareVsync(true);
             mScheduler->onScreenReleased(mAppConnectionHandle);
         }
@@ -4198,15 +4196,14 @@
         getHwComposer().setPowerMode(*displayId, mode);
         mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing on this display
-    } else if (mode == HWC_POWER_MODE_DOZE ||
-               mode == HWC_POWER_MODE_NORMAL) {
+    } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
         // Update display while dozing
         getHwComposer().setPowerMode(*displayId, mode);
-        if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
+        if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
         }
-    } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
+    } else if (mode == hal::PowerMode::DOZE_SUSPEND) {
         // Leave display going to doze
         if (display->isPrimary()) {
             mScheduler->disableHardwareVsync(true);
@@ -4221,14 +4218,14 @@
     if (display->isPrimary()) {
         mTimeStats->setPowerMode(mode);
         mRefreshRateStats->setPowerMode(mode);
-        mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL);
+        mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
     }
 
     ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
-    postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+    schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4236,13 +4233,11 @@
         } else if (display->isVirtual()) {
             ALOGW("Attempt to set power mode %d for virtual display", mode);
         } else {
-            setPowerModeInternal(display, mode);
+            setPowerModeInternal(display, static_cast<hal::PowerMode>(mode));
         }
-    }));
+    }).wait();
 }
 
-// ---------------------------------------------------------------------------
-
 status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
                                 bool asProto) NO_THREAD_SAFETY_ANALYSIS {
     std::string result;
@@ -4397,17 +4392,19 @@
     scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
     StringAppendF(&result,
                   "DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
-                  ", min: %.2f Hz, max: %.2f Hz",
-                  policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate);
+                  ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+                  policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
+                  policy.appRequestRange.min, policy.appRequestRange.max);
     StringAppendF(&result, "(config override by backdoor: %s)\n\n",
                   mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
     scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
     if (currentPolicy != policy) {
         StringAppendF(&result,
                       "DesiredDisplayConfigSpecs (Override): default config ID: %d"
-                      ", min: %.2f Hz, max: %.2f Hz\n\n",
-                      currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
-                      currentPolicy.maxRefreshRate);
+                      ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+                      currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+                      currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+                      currentPolicy.appRequestRange.max);
     }
 
     mScheduler->dump(mAppConnectionHandle, result);
@@ -4603,20 +4600,21 @@
 }
 
 LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
-    LayersProto layersProto;
-    postMessageSync(new LambdaMessage([&] { layersProto = dumpDrawingStateProto(traceFlags); }));
-    return layersProto;
+    return schedule([=] { return dumpDrawingStateProto(traceFlags); }).get();
 }
 
 void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
     result.append("Offscreen Layers:\n");
-    postMessageSync(new LambdaMessage([&]() {
-        for (Layer* offscreenLayer : mOffscreenLayers) {
-            offscreenLayer->traverse(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-                layer->dumpCallingUidPid(result);
-            });
-        }
-    }));
+    result.append(schedule([this] {
+                      std::string result;
+                      for (Layer* offscreenLayer : mOffscreenLayers) {
+                          offscreenLayer->traverse(LayerVector::StateSet::Drawing,
+                                                   [&](Layer* layer) {
+                                                       layer->dumpCallingUidPid(result);
+                                                   });
+                      }
+                      return result;
+                  }).get());
 }
 
 void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
@@ -5299,7 +5297,7 @@
 
     // Update the overlay on the main thread to avoid race conditions with
     // mRefreshRateConfigs->getCurrentRefreshRate()
-    postMessageAsync(new LambdaMessage([this, expired]() NO_THREAD_SAFETY_ANALYSIS {
+    static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
         if (mRefreshRateOverlay) {
             const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
             const bool timerExpired = kernelTimerEnabled && expired;
@@ -5572,7 +5570,7 @@
     {
         Mutex::Autolock lock(mStateLock);
 
-        parent = fromHandle(layerHandleBinder);
+        parent = fromHandleLocked(layerHandleBinder).promote();
         if (parent == nullptr || parent->isRemovedFromCurrentState()) {
             ALOGE("captureLayers called with an invalid or removed parent");
             return NAME_NOT_FOUND;
@@ -5605,7 +5603,7 @@
         reqHeight = crop.height() * frameScale;
 
         for (const auto& handle : excludeHandles) {
-            sp<Layer> excludeLayer = fromHandle(handle);
+            sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
             if (excludeLayer != nullptr) {
                 excludeLayers.emplace(excludeLayer);
             } else {
@@ -5675,68 +5673,41 @@
                                              usage, "screenshot");
 
     return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform,
-                               outCapturedSecureLayers);
+                               false /* regionSampling */, outCapturedSecureLayers);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
                                              TraverseLayersFunction traverseLayers,
                                              const sp<GraphicBuffer>& buffer,
-                                             bool useIdentityTransform,
+                                             bool useIdentityTransform, bool regionSampling,
                                              bool& outCapturedSecureLayers) {
-    // This mutex protects syncFd and captureResult for communication of the return values from the
-    // main thread back to this Binder thread
-    std::mutex captureMutex;
-    std::condition_variable captureCondition;
-    std::unique_lock<std::mutex> captureLock(captureMutex);
-    int syncFd = -1;
-    std::optional<status_t> captureResult;
-
     const int uid = IPCThreadState::self()->getCallingUid();
     const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
 
-    sp<LambdaMessage> message = new LambdaMessage([&] {
-        // If there is a refresh pending, bug out early and tell the binder thread to try again
-        // after the refresh.
-        if (mRefreshPending) {
-            ATRACE_NAME("Skipping screenshot for now");
-            std::unique_lock<std::mutex> captureLock(captureMutex);
-            captureResult = std::make_optional<status_t>(EAGAIN);
-            captureCondition.notify_one();
-            return;
-        }
+    status_t result;
+    int syncFd;
 
-        status_t result = NO_ERROR;
-        int fd = -1;
-        {
-            Mutex::Autolock _l(mStateLock);
-            renderArea.render([&] {
-                result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
-                                                 useIdentityTransform, forSystem, &fd,
-                                                 outCapturedSecureLayers);
-            });
-        }
+    do {
+        std::tie(result, syncFd) =
+                schedule([&] {
+                    if (mRefreshPending) {
+                        ATRACE_NAME("Skipping screenshot for now");
+                        return std::make_pair(EAGAIN, -1);
+                    }
 
-        {
-            std::unique_lock<std::mutex> captureLock(captureMutex);
-            syncFd = fd;
-            captureResult = std::make_optional<status_t>(result);
-            captureCondition.notify_one();
-        }
-    });
+                    status_t result = NO_ERROR;
+                    int fd = -1;
 
-    status_t result = postMessageAsync(message);
-    if (result == NO_ERROR) {
-        captureCondition.wait(captureLock, [&] { return captureResult; });
-        while (*captureResult == EAGAIN) {
-            captureResult.reset();
-            result = postMessageAsync(message);
-            if (result != NO_ERROR) {
-                return result;
-            }
-            captureCondition.wait(captureLock, [&] { return captureResult; });
-        }
-        result = *captureResult;
-    }
+                    Mutex::Autolock lock(mStateLock);
+                    renderArea.render([&] {
+                        result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
+                                                         useIdentityTransform, forSystem, &fd,
+                                                         regionSampling, outCapturedSecureLayers);
+                    });
+
+                    return std::make_pair(result, fd);
+                }).get();
+    } while (result == EAGAIN);
 
     if (result == NO_ERROR) {
         sync_wait(syncFd, -1);
@@ -5749,7 +5720,8 @@
 void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
                                             TraverseLayersFunction traverseLayers,
                                             const sp<GraphicBuffer>& buffer,
-                                            bool useIdentityTransform, int* outSyncFd) {
+                                            bool useIdentityTransform, bool regionSampling,
+                                            int* outSyncFd) {
     ATRACE_CALL();
 
     const auto reqWidth = renderArea.getReqWidth();
@@ -5805,6 +5777,12 @@
             for (auto& settings : results) {
                 settings.geometry.positionTransform =
                         transform.asMatrix4() * settings.geometry.positionTransform;
+                // There's no need to process blurs when we're executing region sampling,
+                // we're just trying to understand what we're drawing, and doing so without
+                // blurs is already a pretty good approximation.
+                if (regionSampling) {
+                    settings.backgroundBlurRadius = 0;
+                }
             }
             clientCompositionLayers.insert(clientCompositionLayers.end(),
                                            std::make_move_iterator(results.begin()),
@@ -5842,7 +5820,8 @@
                                                  TraverseLayersFunction traverseLayers,
                                                  const sp<GraphicBuffer>& buffer,
                                                  bool useIdentityTransform, bool forSystem,
-                                                 int* outSyncFd, bool& outCapturedSecureLayers) {
+                                                 int* outSyncFd, bool regionSampling,
+                                                 bool& outCapturedSecureLayers) {
     ATRACE_CALL();
 
     traverseLayers([&](Layer* layer) {
@@ -5857,7 +5836,8 @@
         ALOGW("FB is protected: PERMISSION_DENIED");
         return PERMISSION_DENIED;
     }
-    renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, outSyncFd);
+    renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, regionSampling,
+                           outSyncFd);
     return NO_ERROR;
 }
 
@@ -5960,9 +5940,11 @@
     }
     scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
 
-    ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
-          currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
-          currentPolicy.maxRefreshRate);
+    ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]"
+          " expandedRange: [%.0f %.0f]",
+          currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+          currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+          currentPolicy.appRequestRange.max);
 
     // TODO(b/140204874): This hack triggers a notification that something has changed, so
     // that listeners that care about a change in allowed configs can get the notification.
@@ -5995,45 +5977,50 @@
 }
 
 status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                      int32_t defaultConfig, float minRefreshRate,
-                                                      float maxRefreshRate) {
+                                                      int32_t defaultConfig,
+                                                      float primaryRefreshRateMin,
+                                                      float primaryRefreshRateMax,
+                                                      float appRequestRefreshRateMin,
+                                                      float appRequestRefreshRateMax) {
     ATRACE_CALL();
 
     if (!displayToken) {
         return BAD_VALUE;
     }
 
-    status_t result = NAME_NOT_FOUND;
-
-    postMessageSync(new LambdaMessage([&]() {
+    auto future = schedule([=]() -> status_t {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set desired display configs for invalid display token %p",
                   displayToken.get());
+            return NAME_NOT_FOUND;
         } else if (display->isVirtual()) {
             ALOGW("Attempt to set desired display configs for virtual display");
-            result = INVALID_OPERATION;
+            return INVALID_OPERATION;
         } else {
-            result = setDesiredDisplayConfigSpecsInternal(display,
-                                                          scheduler::RefreshRateConfigs::
-                                                                  Policy{HwcConfigIndexType(
-                                                                                 defaultConfig),
-                                                                         minRefreshRate,
-                                                                         maxRefreshRate},
-                                                          /*overridePolicy=*/false);
-        }
-    }));
+            using Policy = scheduler::RefreshRateConfigs::Policy;
+            const Policy policy{HwcConfigIndexType(defaultConfig),
+                                {primaryRefreshRateMin, primaryRefreshRateMax},
+                                {appRequestRefreshRateMin, appRequestRefreshRateMax}};
+            constexpr bool kOverridePolicy = false;
 
-    return result;
+            return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
+        }
+    });
+
+    return future.get();
 }
 
 status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                       int32_t* outDefaultConfig,
-                                                      float* outMinRefreshRate,
-                                                      float* outMaxRefreshRate) {
+                                                      float* outPrimaryRefreshRateMin,
+                                                      float* outPrimaryRefreshRateMax,
+                                                      float* outAppRequestRefreshRateMin,
+                                                      float* outAppRequestRefreshRateMax) {
     ATRACE_CALL();
 
-    if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) {
+    if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
+        !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
         return BAD_VALUE;
     }
 
@@ -6047,8 +6034,10 @@
         scheduler::RefreshRateConfigs::Policy policy =
                 mRefreshRateConfigs->getDisplayManagerPolicy();
         *outDefaultConfig = policy.defaultConfig.value();
-        *outMinRefreshRate = policy.minRefreshRate;
-        *outMaxRefreshRate = policy.maxRefreshRate;
+        *outPrimaryRefreshRateMin = policy.primaryRange.min;
+        *outPrimaryRefreshRateMax = policy.primaryRange.max;
+        *outAppRequestRefreshRateMin = policy.appRequestRange.min;
+        *outAppRequestRefreshRateMax = policy.appRequestRange.max;
         return NO_ERROR;
     } else if (display->isVirtual()) {
         return INVALID_OPERATION;
@@ -6058,8 +6047,10 @@
 
         *outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId);
         auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod();
-        *outMinRefreshRate = 1e9f / vsyncPeriod;
-        *outMaxRefreshRate = 1e9f / vsyncPeriod;
+        *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
+        *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
+        *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod;
+        *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod;
         return NO_ERROR;
     }
 }
@@ -6068,7 +6059,12 @@
     mFlinger->setInputWindowsFinished();
 }
 
-sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+    Mutex::Autolock _l(mStateLock);
+    return fromHandleLocked(handle);
+}
+
+wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) {
     BBinder* b = nullptr;
     if (handle) {
         b = handle->localBinder();
@@ -6078,7 +6074,7 @@
     }
     auto it = mLayersByLocalBinderToken.find(b);
     if (it != mLayersByLocalBinderToken.end()) {
-        return it->second.promote();
+        return it->second;
     }
     return nullptr;
 }
@@ -6148,7 +6144,7 @@
         return BAD_VALUE;
     }
 
-    postMessageAsync(new LambdaMessage([=]() NO_THREAD_SAFETY_ANALYSIS {
+    static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
         Mutex::Autolock lock(mStateLock);
         if (authenticateSurfaceTextureLocked(surface)) {
             sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
@@ -6171,8 +6167,11 @@
     if (!outToken) {
         return BAD_VALUE;
     }
-    status_t result = NO_ERROR;
-    postMessageSync(new LambdaMessage([&]() {
+
+    auto future = schedule([this] {
+        status_t result = NO_ERROR;
+        sp<IBinder> token;
+
         if (mFrameRateFlexibilityTokenCount == 0) {
             // |mStateLock| not needed as we are on the main thread
             const auto display = getDefaultDisplayDeviceLocked();
@@ -6186,8 +6185,8 @@
             overridePolicy.defaultConfig =
                     mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig;
             overridePolicy.allowGroupSwitching = true;
-            result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy,
-                                                          /*overridePolicy=*/true);
+            constexpr bool kOverridePolicy = true;
+            result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy, kOverridePolicy);
         }
 
         if (result == NO_ERROR) {
@@ -6204,17 +6203,22 @@
             //   2. The frame rate flexibility token is acquired/released only by CTS tests, so even
             //   if condition 1 were changed, the problem would only show up when running CTS tests,
             //   not on end user devices, so we could spot it and fix it without serious impact.
-            *outToken = new FrameRateFlexibilityToken(
+            token = new FrameRateFlexibilityToken(
                     [this]() { onFrameRateFlexibilityTokenReleased(); });
             ALOGD("Frame rate flexibility token acquired. count=%d",
                   mFrameRateFlexibilityTokenCount);
         }
-    }));
+
+        return std::make_pair(result, token);
+    });
+
+    status_t result;
+    std::tie(result, *outToken) = future.get();
     return result;
 }
 
 void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() {
-    postMessageAsync(new LambdaMessage([&]() {
+    static_cast<void>(schedule([this] {
         LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0,
                             "Failed tracking frame rate flexibility tokens");
         mFrameRateFlexibilityTokenCount--;
@@ -6222,8 +6226,8 @@
         if (mFrameRateFlexibilityTokenCount == 0) {
             // |mStateLock| not needed as we are on the main thread
             const auto display = getDefaultDisplayDeviceLocked();
-            status_t result =
-                    setDesiredDisplayConfigSpecsInternal(display, {}, /*overridePolicy=*/true);
+            constexpr bool kOverridePolicy = true;
+            status_t result = setDesiredDisplayConfigSpecsInternal(display, {}, kOverridePolicy);
             LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token");
         }
     }));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7aea8fe..4b5a843 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -68,6 +68,7 @@
 #include <atomic>
 #include <cstdint>
 #include <functional>
+#include <future>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -276,12 +277,9 @@
     // starts SurfaceFlinger main loop in the current thread
     void run() ANDROID_API;
 
-    // post an asynchronous message to the main thread
-    status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
-
-    // post a synchronous message to the main thread
-    status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0)
-            EXCLUDES(mStateLock);
+    // Schedule an asynchronous or synchronous task on the main thread.
+    template <typename F, typename T = std::invoke_result_t<F>>
+    [[nodiscard]] std::future<T> schedule(F&&);
 
     // force full composition on all displays
     void repaintEverything();
@@ -315,7 +313,7 @@
     // called on the main thread by MessageQueue when an internal message
     // is received
     // TODO: this should be made accessible only to MessageQueue
-    void onMessageReceived(int32_t what, nsecs_t when);
+    void onMessageReceived(int32_t what, nsecs_t expectedVSyncTime);
 
     renderengine::RenderEngine& getRenderEngine() const;
 
@@ -331,7 +329,12 @@
         return mTransactionCompletedThread;
     }
 
-    sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
+    // Converts from a binder handle to a Layer
+    // Returns nullptr if the handle does not point to an existing layer.
+    // Otherwise, returns a weak reference so that callers off the main-thread
+    // won't accidentally hold onto the last strong reference.
+    wp<Layer> fromHandle(const sp<IBinder>& handle);
+    wp<Layer> fromHandleLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
 
     // Inherit from ClientCache::ErasedRecipient
     void bufferErased(const client_cache_t& clientCacheId) override;
@@ -490,10 +493,15 @@
                                        const sp<IRegionSamplingListener>& listener) override;
     status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
     status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
-                                          float minRefreshRate, float maxRefreshRate) override;
+                                          float primaryRefreshRateMin, float primaryRefreshRateMax,
+                                          float appRequestRefreshRateMin,
+                                          float appRequestRefreshRateMax) override;
     status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                          int32_t* outDefaultConfig, float* outMinRefreshRate,
-                                          float* outMaxRefreshRate) override;
+                                          int32_t* outDefaultConfig,
+                                          float* outPrimaryRefreshRateMin,
+                                          float* outPrimaryRefreshRateMax,
+                                          float* outAppRequestRefreshRateMin,
+                                          float* outAppRequestRefreshRateMax) override;
     status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
                                          bool* outSupport) const override;
     status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
@@ -537,7 +545,6 @@
     /* ------------------------------------------------------------------------
      * Message handling
      */
-    void waitForEvent();
     // Can only be called from the main thread or with mStateLock held
     void signalTransaction();
     // Can only be called from the main thread or with mStateLock held
@@ -569,7 +576,8 @@
     // Called when active config is no longer is progress
     void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
     // called on the main thread in response to setPowerMode()
-    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
+    void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
+            REQUIRES(mStateLock);
 
     // Sets the desired display configs.
     status_t setDesiredDisplayConfigSpecsInternal(
@@ -577,14 +585,20 @@
             const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
             EXCLUDES(mStateLock);
 
+    // Handle the INVALIDATE message queue event, latching new buffers and applying
+    // incoming transactions
+    void onMessageInvalidate(nsecs_t expectedVSyncTime);
+
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
 
+    // Handle the REFRESH message queue event, sending the current frame down to RenderEngine and
+    // the Composer HAL for presentation
+    void onMessageRefresh();
+
     // Returns whether a new buffer has been latched (see handlePageFlip())
     bool handleMessageInvalidate();
 
-    void handleMessageRefresh();
-
     void handleTransaction(uint32_t transactionFlags);
     void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
 
@@ -624,7 +638,6 @@
     void commitTransaction() REQUIRES(mStateLock);
     void commitOffscreenLayers();
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
-                                       bool useCachedExpectedPresentTime,
                                        const Vector<ComposerState>& states);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
@@ -638,6 +651,13 @@
             REQUIRES(mStateLock);
     virtual void commitTransactionLocked();
 
+    // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
+    // root layers on a particular display in layer-coordinate space. The
+    // layers (and effectively their children) will be clipped against this
+    // rectangle. The base behavior is to clip to the visible region of the
+    // display.
+    virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const;
+
 private:
     /* ------------------------------------------------------------------------
      * Layer management
@@ -696,19 +716,20 @@
 
     void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                 const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
-                                int* outSyncFd);
+                                bool regionSampling, int* outSyncFd);
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                  sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
                                  bool useIdentityTransform, bool& outCapturedSecureLayers);
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                  const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
-                                 bool& outCapturedSecureLayers);
+                                 bool regionSampling, bool& outCapturedSecureLayers);
     const sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack);
     const sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack);
     status_t captureScreenImplLocked(const RenderArea& renderArea,
                                      TraverseLayersFunction traverseLayers,
                                      const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
-                                     bool forSystem, int* outSyncFd, bool& outCapturedSecureLayers);
+                                     bool forSystem, int* outSyncFd, bool regionSampling,
+                                     bool& outCapturedSecureLayers);
     void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
                                  const LayerVector::Visitor& visitor);
 
@@ -846,9 +867,9 @@
     // Must be called on the main thread.
     nsecs_t previousFramePresentTime();
 
-    // Populates the expected present time for this frame. For negative offsets, performs a
+    // Calculates the expected present time for this frame. For negative offsets, performs a
     // correction using the predicted vsync for the next frame instead.
-    void populateExpectedPresentTime(nsecs_t now);
+    nsecs_t calculateExpectedPresentTime(nsecs_t now) const;
 
     /*
      * Display identification
@@ -990,6 +1011,8 @@
     size_t mGraphicBufferProducerListSizeLogThreshold =
             static_cast<size_t>(0.95 * static_cast<double>(MAX_LAYERS));
 
+    void removeGraphicBufferProducerAsync(const wp<IBinder>&);
+
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved = false;
     bool mLayersAdded = false;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index d27fbb4..3901757 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -4,6 +4,7 @@
         "TimeStats.cpp",
     ],
     shared_libs: [
+        "android.hardware.graphics.composer@2.4",
         "libbase",
         "libcutils",
         "liblog",
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 80fe180..37194c6 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -321,7 +321,7 @@
     if (!mEnabled.load()) return;
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (mPowerTime.powerMode == HWC_POWER_MODE_NORMAL) {
+    if (mPowerTime.powerMode == PowerMode::ON) {
         mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
     }
 }
@@ -692,12 +692,13 @@
     int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
 
     switch (mPowerTime.powerMode) {
-        case HWC_POWER_MODE_NORMAL:
+        case PowerMode::ON:
             mTimeStats.displayOnTime += elapsedTime;
             break;
-        case HWC_POWER_MODE_OFF:
-        case HWC_POWER_MODE_DOZE:
-        case HWC_POWER_MODE_DOZE_SUSPEND:
+        case PowerMode::OFF:
+        case PowerMode::DOZE:
+        case PowerMode::DOZE_SUSPEND:
+        case PowerMode::ON_SUSPEND:
         default:
             break;
     }
@@ -705,7 +706,7 @@
     mPowerTime.prevTime = curTime;
 }
 
-void TimeStats::setPowerMode(int32_t powerMode) {
+void TimeStats::setPowerMode(PowerMode powerMode) {
     if (!mEnabled.load()) {
         std::lock_guard<std::mutex> lock(mMutex);
         mPowerTime.powerMode = powerMode;
@@ -793,8 +794,8 @@
         return;
     }
 
-    if (mPowerTime.powerMode != HWC_POWER_MODE_NORMAL) {
-        // Try flushing the last present fence on HWC_POWER_MODE_NORMAL.
+    if (mPowerTime.powerMode != PowerMode::ON) {
+        // Try flushing the last present fence on PowerMode::ON.
         flushAvailableGlobalRecordsToStatsLocked();
         mGlobalRecord.presentFences.clear();
         mGlobalRecord.prevPresentTime = 0;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index eb48353..8de5d0c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -16,7 +16,15 @@
 
 #pragma once
 
-#include <hardware/hwcomposer_defs.h>
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
 #include <stats_event.h>
 #include <stats_pull_atom_callback.h>
 #include <statslog.h>
@@ -105,7 +113,8 @@
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
     virtual void removeTimeRecord(int32_t layerId, uint64_t frameNumber) = 0;
 
-    virtual void setPowerMode(int32_t powerMode) = 0;
+    virtual void setPowerMode(
+            hardware::graphics::composer::V2_4::IComposerClient::PowerMode powerMode) = 0;
     // Source of truth is RefrehRateStats.
     virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
     virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
@@ -114,6 +123,8 @@
 namespace impl {
 
 class TimeStats : public android::TimeStats {
+    using PowerMode = android::hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
+
     struct FrameTime {
         uint64_t frameNumber = 0;
         nsecs_t postTime = 0;
@@ -144,7 +155,7 @@
     };
 
     struct PowerTime {
-        int32_t powerMode = HWC_POWER_MODE_OFF;
+        PowerMode powerMode = PowerMode::OFF;
         nsecs_t prevTime = 0;
     };
 
@@ -247,7 +258,8 @@
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
     void removeTimeRecord(int32_t layerId, uint64_t frameNumber) override;
 
-    void setPowerMode(int32_t powerMode) override;
+    void setPowerMode(
+            hardware::graphics::composer::V2_4::IComposerClient::PowerMode powerMode) override;
     // Source of truth is RefrehRateStats.
     void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
     void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index c145a39..4e7f67d 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -16,10 +16,13 @@
 
 #pragma once
 #include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
 #include <utils/Trace.h>
 #include <cmath>
 #include <string>
 
+namespace android {
+
 template <typename T>
 class TracedOrdinal {
 public:
@@ -27,9 +30,8 @@
                   "Type is not supported. Please test it with systrace before adding "
                   "it to the list.");
 
-    TracedOrdinal(const std::string& name, T initialValue)
-          : mName(name),
-            mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())),
+    TracedOrdinal(std::string name, T initialValue)
+          : mName(std::move(name)),
             mHasGoneNegative(std::signbit(initialValue)),
             mData(initialValue) {
         trace();
@@ -46,6 +48,14 @@
 
 private:
     void trace() {
+        if (CC_LIKELY(!ATRACE_ENABLED())) {
+            return;
+        }
+
+        if (mNameNegative.empty()) {
+            mNameNegative = base::StringPrintf("%sNegative", mName.c_str());
+        }
+
         if (!std::signbit(mData)) {
             ATRACE_INT64(mName.c_str(), int64_t(mData));
             if (mHasGoneNegative) {
@@ -58,7 +68,9 @@
     }
 
     const std::string mName;
-    const std::string mNameNegative;
+    std::string mNameNegative;
     bool mHasGoneNegative;
     T mData;
 };
+
+} // namespace android
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index d3942e8..575e70d 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -4,7 +4,7 @@
     group graphics drmrpc readproc
     capabilities SYS_NICE
     onrestart restart zygote
-    writepid /dev/stune/foreground/tasks
+    task_profiles HighPerformance
     socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
     socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
     socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 507d28b..c136708 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -215,14 +215,21 @@
 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);
+    float primaryFpsMin;
+    float primaryFpsMax;
+    float appRequestFpsMin;
+    float appRequestFpsMax;
+    status_t res =
+            SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+                                                                &primaryFpsMin, &primaryFpsMax,
+                                                                &appRequestFpsMin,
+                                                                &appRequestFpsMax);
     ASSERT_EQ(res, NO_ERROR);
     std::function<status_t()> condition = [=]() {
-        return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps,
-                                                                   maxFps);
+        return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+                                                                   primaryFpsMin, primaryFpsMax,
+                                                                   appRequestFpsMin,
+                                                                   appRequestFpsMax);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 0ed2ffb..debfe83 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -39,11 +39,16 @@
 
 TEST_F(RefreshRateRangeTest, setAllConfigs) {
     int32_t initialDefaultConfig;
-    float initialMin;
-    float initialMax;
+    float initialPrimaryMin;
+    float initialPrimaryMax;
+    float initialAppRequestMin;
+    float initialAppRequestMax;
     status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
                                                                        &initialDefaultConfig,
-                                                                       &initialMin, &initialMax);
+                                                                       &initialPrimaryMin,
+                                                                       &initialPrimaryMax,
+                                                                       &initialAppRequestMin,
+                                                                       &initialAppRequestMax);
     ASSERT_EQ(res, NO_ERROR);
 
     Vector<DisplayConfig> configs;
@@ -53,22 +58,33 @@
     for (size_t i = 0; i < configs.size(); i++) {
         res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
                                                                   configs[i].refreshRate,
+                                                                  configs[i].refreshRate,
+                                                                  configs[i].refreshRate,
                                                                   configs[i].refreshRate);
         ASSERT_EQ(res, NO_ERROR);
 
         int defaultConfig;
-        float minRefreshRate;
-        float maxRefreshRate;
+        float primaryRefreshRateMin;
+        float primaryRefreshRateMax;
+        float appRequestRefreshRateMin;
+        float appRequestRefreshRateMax;
         res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
-                                                                  &minRefreshRate, &maxRefreshRate);
+                                                                  &primaryRefreshRateMin,
+                                                                  &primaryRefreshRateMax,
+                                                                  &appRequestRefreshRateMin,
+                                                                  &appRequestRefreshRateMax);
         ASSERT_EQ(res, NO_ERROR);
         ASSERT_EQ(defaultConfig, i);
-        ASSERT_EQ(minRefreshRate, configs[i].refreshRate);
-        ASSERT_EQ(maxRefreshRate, configs[i].refreshRate);
+        ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
+        ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
+        ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
+        ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
     }
 
     res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
-                                                              initialMin, initialMax);
+                                                              initialPrimaryMin, initialPrimaryMax,
+                                                              initialAppRequestMin,
+                                                              initialAppRequestMax);
     ASSERT_EQ(res, NO_ERROR);
 }
 
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index ff403f6..2861013 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -23,7 +23,6 @@
         "libcutils",
         "libfmq",
         "libgui",
-        "libhardware",
         "libhidlbase",
         "liblayers_proto",
         "liblog",
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 32c58ad..a03fd89 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -443,6 +443,8 @@
                 EXPECT_EQ(NO_ERROR,
                           SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
                                                                               config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
                                                                               config.refreshRate));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -547,6 +549,8 @@
                 EXPECT_EQ(NO_ERROR,
                           SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
                                                                               config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
                                                                               config.refreshRate));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -659,9 +663,11 @@
             const auto& config = configs[i];
             if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
-                                                                              configs[i].refreshRate,
-                                                                              configs[i].refreshRate));
+                          SurfaceComposerClient::
+                                  setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+                                                               configs[i].refreshRate,
+                                                               configs[i].refreshRate,
+                                                               configs[i].refreshRate));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
@@ -706,6 +712,8 @@
                 EXPECT_EQ(NO_ERROR,
                           SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
                                                                               config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
                                                                               config.refreshRate));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -751,6 +759,8 @@
                 EXPECT_EQ(NO_ERROR,
                           SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
                                                                               config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
                                                                               config.refreshRate));
                 waitForDisplayTransaction();
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 2f2fb20..7574ff1 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -48,6 +48,7 @@
         "LayerHistoryTestV2.cpp",
         "LayerMetadataTest.cpp",
         "PhaseOffsetsTest.cpp",
+        "PromiseTest.cpp",
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
         "SetFrameRateTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 51412d2..2785397 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -52,6 +52,12 @@
 
 namespace hal = android::hardware::graphics::composer::hal;
 
+using hal::Error;
+using hal::IComposer;
+using hal::IComposerClient;
+using hal::PowerMode;
+using hal::Transform;
+
 using testing::_;
 using testing::AtLeast;
 using testing::Between;
@@ -67,11 +73,6 @@
 using testing::ReturnRef;
 using testing::SetArgPointee;
 
-using android::Hwc2::Error;
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-using android::Hwc2::Transform;
-
 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
 using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
 
@@ -230,6 +231,7 @@
     const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
     constexpr bool useIdentityTransform = true;
     constexpr bool forSystem = true;
+    constexpr bool regionSampling = false;
 
     DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
                                  DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
@@ -248,7 +250,7 @@
     int fd = -1;
     status_t result =
             mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
-                                             useIdentityTransform, forSystem, &fd);
+                                             useIdentityTransform, forSystem, &fd, regionSampling);
     if (fd >= 0) {
         close(fd);
     }
@@ -265,13 +267,10 @@
 template <typename Derived>
 struct BaseDisplayVariant {
     static constexpr bool IS_SECURE = true;
-    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+    static constexpr hal::PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
 
     static void setupPreconditions(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setPowerMode(HWC_DISPLAY,
-                                 static_cast<Hwc2::IComposerClient::PowerMode>(
-                                         Derived::INIT_POWER_MODE)))
+        EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY, Derived::INIT_POWER_MODE))
                 .WillOnce(Return(Error::NONE));
 
         FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, true /* isPrimary */)
@@ -438,7 +437,7 @@
 };
 
 struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
-    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+    static constexpr hal::PowerMode INIT_POWER_MODE = hal::PowerMode::OFF;
 
     template <typename Case>
     static void setupPreconditionCallExpectations(CompositionTest*) {}
@@ -543,7 +542,7 @@
 
         EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
         enqueueBuffer(test, layer);
-        Mock::VerifyAndClear(test->mMessageQueue);
+        Mock::VerifyAndClearExpectations(test->mMessageQueue);
 
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
         bool ignoredRecomputeVisibleRegions;
@@ -835,7 +834,7 @@
 struct BaseLayerVariant {
     template <typename L, typename F>
     static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(0);
 
         sp<L> layer = factory();
 
@@ -844,7 +843,7 @@
 
         Mock::VerifyAndClear(test->mComposer);
         Mock::VerifyAndClear(test->mRenderEngine);
-        Mock::VerifyAndClear(test->mMessageQueue);
+        Mock::VerifyAndClearExpectations(test->mMessageQueue);
 
         auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
         layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
@@ -945,7 +944,7 @@
     }
 
     static void cleanupInjectedLayers(CompositionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(1);
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1);
         Base::cleanupInjectedLayers(test);
     }
 
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 2e705da..afebc40 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -43,7 +43,7 @@
     void createDispSync();
     void createDispSyncSource();
 
-    void onVSyncEvent(nsecs_t when) override;
+    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
 
     std::unique_ptr<mock::DispSync> mDispSync;
     std::unique_ptr<DispSyncSource> mDispSyncSource;
@@ -66,7 +66,7 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when) {
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) {
     ALOGD("onVSyncEvent: %" PRId64, when);
 
     mVSyncEventCallRecorder.recordCall(when);
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index b530f8e..cc6a60c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -22,6 +22,8 @@
 
 #include "DisplayHardware/DisplayIdentification.h"
 
+using ::testing::ElementsAre;
+
 namespace android {
 namespace {
 
@@ -209,12 +211,11 @@
     EXPECT_EQ(41, edid->manufactureWeek);
     ASSERT_TRUE(edid->cea861Block);
     ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
-    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress);
     auto physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
-    EXPECT_EQ(2, physicalAddress->a);
-    EXPECT_EQ(0, physicalAddress->b);
-    EXPECT_EQ(0, physicalAddress->c);
-    EXPECT_EQ(0, physicalAddress->d);
+    EXPECT_EQ(2, physicalAddress.a);
+    EXPECT_EQ(0, physicalAddress.b);
+    EXPECT_EQ(0, physicalAddress.c);
+    EXPECT_EQ(0, physicalAddress.d);
 
     edid = parseEdid(getPanasonicTvEdid());
     ASSERT_TRUE(edid);
@@ -227,12 +228,11 @@
     EXPECT_EQ(0, edid->manufactureWeek);
     ASSERT_TRUE(edid->cea861Block);
     ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
-    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress);
     physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
-    EXPECT_EQ(2, physicalAddress->a);
-    EXPECT_EQ(0, physicalAddress->b);
-    EXPECT_EQ(0, physicalAddress->c);
-    EXPECT_EQ(0, physicalAddress->d);
+    EXPECT_EQ(2, physicalAddress.a);
+    EXPECT_EQ(0, physicalAddress.b);
+    EXPECT_EQ(0, physicalAddress.c);
+    EXPECT_EQ(0, physicalAddress.d);
 
     edid = parseEdid(getHisenseTvEdid());
     ASSERT_TRUE(edid);
@@ -245,12 +245,11 @@
     EXPECT_EQ(18, edid->manufactureWeek);
     ASSERT_TRUE(edid->cea861Block);
     ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
-    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress);
     physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
-    EXPECT_EQ(1, physicalAddress->a);
-    EXPECT_EQ(2, physicalAddress->b);
-    EXPECT_EQ(3, physicalAddress->c);
-    EXPECT_EQ(4, physicalAddress->d);
+    EXPECT_EQ(1, physicalAddress.a);
+    EXPECT_EQ(2, physicalAddress.b);
+    EXPECT_EQ(3, physicalAddress.c);
+    EXPECT_EQ(4, physicalAddress.d);
 
     edid = parseEdid(getCtlDisplayEdid());
     ASSERT_TRUE(edid);
@@ -326,6 +325,7 @@
         EXPECT_EQ("12610", info.productId);
         ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
         EXPECT_EQ(2011, std::get<ManufactureYear>(info.manufactureOrModelDate).year);
+        EXPECT_TRUE(info.relativeAddress.empty());
     }
     {
         const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEdid());
@@ -339,6 +339,7 @@
         const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
         EXPECT_EQ(2012, date.year);
         EXPECT_EQ(2, date.week);
+        EXPECT_TRUE(info.relativeAddress.empty());
     }
     {
         const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEedid());
@@ -352,6 +353,7 @@
         const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
         EXPECT_EQ(2011, date.year);
         EXPECT_EQ(41, date.week);
+        EXPECT_THAT(info.relativeAddress, ElementsAre(2, 0, 0, 0));
     }
     {
         const auto displayIdInfo = parseDisplayIdentificationData(0, getPanasonicTvEdid());
@@ -364,6 +366,7 @@
         ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
         const auto& date = std::get<ManufactureYear>(info.manufactureOrModelDate);
         EXPECT_EQ(2019, date.year);
+        EXPECT_THAT(info.relativeAddress, ElementsAre(2, 0, 0, 0));
     }
     {
         const auto displayIdInfo = parseDisplayIdentificationData(0, getHisenseTvEdid());
@@ -377,6 +380,7 @@
         const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
         EXPECT_EQ(2019, date.year);
         EXPECT_EQ(18, date.week);
+        EXPECT_THAT(info.relativeAddress, ElementsAre(1, 2, 3, 4));
     }
     {
         const auto displayIdInfo = parseDisplayIdentificationData(0, getCtlDisplayEdid());
@@ -388,6 +392,7 @@
         EXPECT_EQ("9373", info.productId);
         ASSERT_TRUE(std::holds_alternative<ModelYear>(info.manufactureOrModelDate));
         EXPECT_EQ(2013, std::get<ModelYear>(info.manufactureOrModelDate).year);
+        EXPECT_TRUE(info.relativeAddress.empty());
     }
 }
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 3cb0732..f41b10e 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -92,7 +92,7 @@
 constexpr int32_t DEFAULT_DPI = 320;
 constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
 
-constexpr int HWC_POWER_MODE_LEET = 1337; // An out of range power mode value
+constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
 
 /* ------------------------------------------------------------------------
  * Boolean avoidance
@@ -353,8 +353,8 @@
     static std::optional<DisplayId> get() {
         if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
             return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
-                                                ? HWC_DISPLAY_PRIMARY
-                                                : HWC_DISPLAY_EXTERNAL);
+                                                ? LEGACY_DISPLAY_TYPE_PRIMARY
+                                                : LEGACY_DISPLAY_TYPE_EXTERNAL);
         }
 
         const auto info =
@@ -518,7 +518,7 @@
 
     // The HWC active configuration id
     static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
-    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+    static constexpr PowerMode INIT_POWER_MODE = PowerMode::ON;
 
     static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
         test->mFlinger.mutablePendingHotplugEvents().emplace_back(
@@ -544,8 +544,7 @@
         EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
                                 Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    setPowerMode(HWC_DISPLAY_ID, static_cast<PowerMode>(INIT_POWER_MODE)))
+        EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
                 .WillOnce(Return(Error::NONE));
         injectHwcDisplayWithNoDefaultCapabilities(test);
     }
@@ -3153,10 +3152,10 @@
     EXPECT_EQ(0u, primaryDisplayState.width);
     EXPECT_EQ(0u, primaryDisplayState.height);
 
-    // The display should be set to HWC_POWER_MODE_NORMAL
+    // The display should be set to PowerMode::ON
     ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
     auto displayDevice = primaryDisplay.mutableDisplayDevice();
-    EXPECT_EQ(HWC_POWER_MODE_NORMAL, displayDevice->getPowerMode());
+    EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
 
     // The display refresh period should be set in the frame tracker.
     FrameStats stats;
@@ -3279,7 +3278,7 @@
 // selected subset which provides complete test coverage of the implementation.
 // --------------------------------------------------------------------
 
-template <int initialPowerMode, int targetPowerMode>
+template <PowerMode initialPowerMode, PowerMode targetPowerMode>
 struct TransitionVariantCommon {
     static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
     static constexpr auto TARGET_POWER_MODE = targetPowerMode;
@@ -3287,8 +3286,7 @@
     static void verifyPostconditions(DisplayTransactionTest*) {}
 };
 
-struct TransitionOffToOnVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_NORMAL> {
+struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
@@ -3304,7 +3302,7 @@
 };
 
 struct TransitionOffToDozeSuspendVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_DOZE_SUSPEND> {
+      : public TransitionVariantCommon<PowerMode::OFF, PowerMode::DOZE_SUSPEND> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
@@ -3318,8 +3316,7 @@
     }
 };
 
-struct TransitionOnToOffVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_OFF> {
+struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
@@ -3333,7 +3330,7 @@
 };
 
 struct TransitionDozeSuspendToOffVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_OFF> {
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -3345,8 +3342,7 @@
     }
 };
 
-struct TransitionOnToDozeVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE> {
+struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -3355,7 +3351,7 @@
 };
 
 struct TransitionDozeSuspendToDozeVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_DOZE> {
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
@@ -3364,8 +3360,7 @@
     }
 };
 
-struct TransitionDozeToOnVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE, HWC_POWER_MODE_NORMAL> {
+struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -3374,7 +3369,7 @@
 };
 
 struct TransitionDozeSuspendToOnVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_NORMAL> {
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
@@ -3384,7 +3379,7 @@
 };
 
 struct TransitionOnToDozeSuspendVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE_SUSPEND> {
+      : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
@@ -3394,7 +3389,7 @@
 };
 
 struct TransitionOnToUnknownVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_LEET> {
+      : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -3419,7 +3414,7 @@
     using DispSync = DispSyncVariant;
     using Transition = TransitionVariant;
 
-    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
+    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
         Display::injectHwcDisplayWithNoDefaultCapabilities(test);
         auto display = Display::makeFakeExistingDisplayInjector(test);
         display.inject();
@@ -3435,13 +3430,14 @@
         EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
     }
 
-    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, int mode) {
+    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
+                                                        PowerMode mode) {
         EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
-        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, mode)).Times(1);
+        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
+                .Times(1);
     }
 
-    static void setupComposerCallExpectations(DisplayTransactionTest* test,
-                                              IComposerClient::PowerMode mode) {
+    static void setupComposerCallExpectations(DisplayTransactionTest* test, PowerMode mode) {
         // Any calls to get the active config will return a default value.
         EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
                 .WillRepeatedly(DoAll(SetArgPointee<1>(Display::HWC_ACTIVE_CONFIG_ID),
@@ -3483,14 +3479,14 @@
     void transitionDisplayCommon();
 };
 
-template <int PowerMode>
+template <PowerMode PowerMode>
 struct PowerModeInitialVSyncEnabled : public std::false_type {};
 
 template <>
-struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_NORMAL> : public std::true_type {};
+struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
 
 template <>
-struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_DOZE> : public std::true_type {};
+struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
 
 template <typename Case>
 void SetPowerModeInternalTest::transitionDisplayCommon() {
@@ -3533,18 +3529,18 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The display is already set to HWC_POWER_MODE_NORMAL
-    display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
+    // The display is already set to PowerMode::ON
+    display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
 
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
 
     // --------------------------------------------------------------------
     // Postconditions
 
-    EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
 }
 
 TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
@@ -3563,18 +3559,18 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The display is set to HWC_POWER_MODE_NORMAL
-    getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_NORMAL);
+    // The display is set to PowerMode::ON
+    getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
 
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_OFF);
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
 
     // --------------------------------------------------------------------
     // Postconditions
 
-    EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ba5c0c2..b90b566 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -258,14 +258,14 @@
 
     // Use the received callback to signal a first vsync event.
     // The interceptor should receive the event, as well as the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // Use the received callback to signal a second vsync event.
     // The interceptor should receive the event, but the the connection should
     // not as it was only interested in the first.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -299,7 +299,7 @@
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the second connection. The first connection should not
     // get the event.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
     expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -314,17 +314,17 @@
 
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // A second event should go to the same places.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // A third event should go to the same places.
-    mCallback->onVSyncEvent(789);
+    mCallback->onVSyncEvent(789, 777);
     expectInterceptCallReceived(789);
     expectVsyncEventReceivedByConnection(789, 3u);
 }
@@ -336,22 +336,22 @@
     expectVSyncSetEnabledCallReceived(true);
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
     // The second event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // The third event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(789);
+    mCallback->onVSyncEvent(789, 777);
     expectInterceptCallReceived(789);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
     // The fourth event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(101112);
+    mCallback->onVSyncEvent(101112, 7847);
     expectInterceptCallReceived(101112);
     expectVsyncEventReceivedByConnection(101112, 4u);
 }
@@ -366,7 +366,7 @@
     mConnection = nullptr;
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -386,13 +386,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor and not by the
     // connection.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
 
@@ -420,7 +420,7 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
     expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
@@ -440,13 +440,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an non-fatal error.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor, and by the connection,
     // which still then returns an non-fatal error.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
 
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
index ce5993a..0b74682 100644
--- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -145,7 +145,9 @@
 
 class TestablePhaseOffsets : public impl::PhaseOffsets {
 public:
-    TestablePhaseOffsets() : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 10'000'000) {}
+    TestablePhaseOffsets()
+          : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {},
+                               10'000'000) {}
 };
 
 class PhaseOffsetsTest : public testing::Test {
diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
new file mode 100644
index 0000000..e4dc1fe
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <future>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "Promise.h"
+
+namespace android {
+namespace {
+
+using Bytes = std::vector<uint8_t>;
+
+Bytes decrement(Bytes bytes) {
+    std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; });
+    return bytes;
+}
+
+} // namespace
+
+TEST(PromiseTest, yield) {
+    EXPECT_EQ(42, promise::yield(42).get());
+
+    auto ptr = std::make_unique<char>('!');
+    auto future = promise::yield(std::move(ptr));
+    EXPECT_EQ('!', *future.get());
+}
+
+TEST(PromiseTest, chain) {
+    std::packaged_task<const char*()> fetchString([] { return "ifmmp-"; });
+
+    std::packaged_task<Bytes(std::string)> appendString([](std::string str) {
+        str += "!xpsme";
+        return Bytes{str.begin(), str.end()};
+    });
+
+    std::packaged_task<std::future<Bytes>(Bytes)> decrementBytes(
+            [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); });
+
+    auto fetch = fetchString.get_future();
+    std::thread fetchThread(std::move(fetchString));
+
+    std::thread appendThread, decrementThread;
+
+    EXPECT_EQ("hello, world",
+              promise::chain(std::move(fetch))
+                      .then([](const char* str) { return std::string(str); })
+                      .then([&](std::string str) {
+                          auto append = appendString.get_future();
+                          appendThread = std::thread(std::move(appendString), std::move(str));
+                          return append;
+                      })
+                      .then([&](Bytes bytes) {
+                          auto decrement = decrementBytes.get_future();
+                          decrementThread = std::thread(std::move(decrementBytes),
+                                                        std::move(bytes));
+                          return decrement;
+                      })
+                      .then([](std::future<Bytes> bytes) { return bytes; })
+                      .then([](const Bytes& bytes) {
+                          return std::string(bytes.begin(), bytes.end());
+                      })
+                      .get());
+
+    fetchThread.join();
+    appendThread.join();
+    decrementThread.join();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 2ceb89c..2b168b2 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -166,8 +166,8 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
-    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0);
-    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0);
+    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
+    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
 }
 
 TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -201,7 +201,7 @@
     ASSERT_EQ(mExpected60Config, minRate60);
     ASSERT_EQ(mExpected60Config, performanceRate60);
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
 
     const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -226,7 +226,7 @@
     ASSERT_EQ(mExpected60Config, minRate60);
     ASSERT_EQ(mExpected60Config, performanceRate60);
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
 
     const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -248,7 +248,7 @@
     ASSERT_EQ(mExpected60Config, minRate);
     ASSERT_EQ(mExpected90Config, performanceRate);
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
 
     auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
     auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -271,7 +271,7 @@
         EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
     }
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
     {
         auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
@@ -298,7 +298,7 @@
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
     EXPECT_EQ(mExpected60Config,
@@ -310,7 +310,7 @@
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
     EXPECT_EQ(mExpected90Config,
@@ -321,7 +321,7 @@
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
     EXPECT_EQ(mExpected60Config,
@@ -334,7 +334,7 @@
               refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_72_90Device, /*currentConfigId=*/
@@ -344,17 +344,17 @@
     // refresh rate.
     auto layers = std::vector<LayerRequirement>{};
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
-                                                             false, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/
+                                                     false, /*idle*/ false, &ignored));
 
     // Current refresh rate can always be changed.
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
-                                                             false, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/
+                                                     false, /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -366,162 +366,162 @@
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Heuristic";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     lr.name = "45Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     lr.name = "30Hz Heuristic";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     lr.name = "24Hz Heuristic";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.name = "";
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_72_90Device,
@@ -532,42 +532,42 @@
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
@@ -583,27 +583,27 @@
     lr2.desiredRefreshRate = 60.0f;
     lr2.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 48.0f;
     lr2.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 48.0f;
     lr2.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
@@ -621,8 +621,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
     EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -631,8 +631,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
     EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -641,8 +641,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "60Hz ExplicitDefault";
     EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -651,8 +651,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -661,8 +661,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitDefault;
@@ -671,8 +671,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::Heuristic;
@@ -681,8 +681,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -691,8 +691,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitDefault;
@@ -701,11 +701,11 @@
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.name = "90Hz ExplicitExactOrMultiple";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60Device,
@@ -716,42 +716,42 @@
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60_72_90Device,
@@ -763,70 +763,70 @@
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
     EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Heuristic";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     lr.name = "45Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     lr.name = "30Hz Heuristic";
     EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     lr.name = "24Hz Heuristic";
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+                                                     /*idle*/ false, &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr.name = "24Hz ExplicitExactOrMultiple";
     EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60_90Device,
@@ -840,55 +840,55 @@
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::Max;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 24.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Max;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Max;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Heuristic;
     lr1.desiredRefreshRate = 15.0f;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Heuristic;
     lr1.desiredRefreshRate = 30.0f;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 45.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -901,8 +901,8 @@
     for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
         lr.desiredRefreshRate = fps;
         const auto& refreshRate =
-                refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                               &ignored);
+                refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                       /*idle*/ false, &ignored);
         printf("%.2fHz chooses %s\n", fps, refreshRate.getName().c_str());
         EXPECT_EQ(mExpected60Config, refreshRate);
     }
@@ -931,7 +931,7 @@
     EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
 }
 
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Explicit) {
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getBestRefreshRate_Explicit) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -947,24 +947,24 @@
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 90.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.desiredRefreshRate = 90.0f;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::Heuristic;
     lr1.desiredRefreshRate = 90.0f;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, testInPolicy) {
@@ -975,7 +975,7 @@
     ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50.0f, 59.998f));
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -988,14 +988,14 @@
     for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
         lr.desiredRefreshRate = fps;
         const auto& refreshRate =
-                refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                               &ignored);
+                refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                       /*idle*/ false, &ignored);
         printf("%.2fHz chooses %s\n", fps, refreshRate.getName().c_str());
         EXPECT_EQ(mExpected90Config, refreshRate);
     }
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -1013,8 +1013,8 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -1023,8 +1023,8 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz ExplicitDefault";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -1032,8 +1032,8 @@
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 30.0f;
@@ -1042,8 +1042,8 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 30.0f;
@@ -1051,8 +1051,8 @@
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
-                                                             &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+                                                     /*idle*/ false, &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
@@ -1072,7 +1072,7 @@
     lr2.vote = LayerVoteType::NoVote;
     lr2.name = "NoVote";
     EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -1080,7 +1080,7 @@
     lr2.vote = LayerVoteType::NoVote;
     lr2.name = "NoVote";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -1088,7 +1088,7 @@
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -1096,7 +1096,7 @@
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored));
 
     // The other layer starts to provide buffers
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -1106,7 +1106,7 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+              refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, touchConsidered) {
@@ -1115,10 +1115,10 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    refreshRateConfigs->getRefreshRateForContentV2({}, false, &touchConsidered);
+    refreshRateConfigs->getBestRefreshRate({}, false, /*idle*/ false, &touchConsidered);
     EXPECT_EQ(false, touchConsidered);
 
-    refreshRateConfigs->getRefreshRateForContentV2({}, true, &touchConsidered);
+    refreshRateConfigs->getBestRefreshRate({}, true, /*idle*/ false, &touchConsidered);
     EXPECT_EQ(true, touchConsidered);
 
     auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
@@ -1130,36 +1130,40 @@
     lr1.desiredRefreshRate = 60.0f;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.name = "NoVote";
-    refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
     EXPECT_EQ(true, touchConsidered);
 
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.desiredRefreshRate = 60.0f;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.name = "NoVote";
-    refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
     EXPECT_EQ(false, touchConsidered);
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.name = "NoVote";
-    refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
     EXPECT_EQ(true, touchConsidered);
 
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.desiredRefreshRate = 60.0f;
-    lr1.name = "60Hz ExplicitExactrMultiple";
+    lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.name = "NoVote";
-    refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
     EXPECT_EQ(false, touchConsidered);
 }
 
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) {
     bool ignored;
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90_72_120Device, /*currentConfigId=*/
@@ -1196,7 +1200,7 @@
         lr.name = ss.str();
 
         const auto& refreshRate =
-                refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored);
+                refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored);
         EXPECT_FLOAT_EQ(refreshRate.getFps(), test.second)
                 << "Expecting " << test.first << "fps => " << test.second << "Hz";
     }
@@ -1215,7 +1219,8 @@
 
     bool touchConsidered;
     ASSERT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered)
+              refreshRateConfigs
+                      ->getBestRefreshRate(layers, false, /*idle*/ false, &touchConsidered)
                       .getConfigId());
 
     RefreshRateConfigs::Policy policy;
@@ -1223,7 +1228,117 @@
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
     ASSERT_EQ(HWC_CONFIG_ID_90,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered)
+              refreshRateConfigs
+                      ->getBestRefreshRate(layers, false, /*idle*/ false, &touchConsidered)
+                      .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    layers[0].name = "Test layer";
+
+    // Return the config ID from calling getBestRefreshRate() for a single layer with the
+    // given voteType and fps.
+    auto getFrameRate = [&](LayerVoteType voteType, float fps,
+                            bool touchActive = false) -> HwcConfigIndexType {
+        layers[0].vote = voteType;
+        layers[0].desiredRefreshRate = fps;
+        bool touchConsidered;
+        return refreshRateConfigs
+                ->getBestRefreshRate(layers, touchActive, /*idle*/ false, &touchConsidered)
+                .getConfigId();
+    };
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+              0);
+    bool touchConsidered;
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              refreshRateConfigs
+                      ->getBestRefreshRate({}, /*touchActive=*/false, /*idle*/ false,
+                                           &touchConsidered)
+                      .getConfigId());
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+
+    // Touch boost should be restricted to the primary range.
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+    // When we're higher than the primary range max due to a layer frame rate setting, touch boost
+    // shouldn't drag us back down to the primary range max.
+    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_90,
+              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+              0);
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+}
+
+TEST_F(RefreshRateConfigsTest, idle) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    layers[0].name = "Test layer";
+
+    auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> HwcConfigIndexType {
+        layers[0].vote = voteType;
+        layers[0].desiredRefreshRate = 90.f;
+        bool touchConsidered;
+        return refreshRateConfigs
+                ->getBestRefreshRate(layers, touchActive, /*idle=*/true, &touchConsidered)
+                .getConfigId();
+    };
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    // Idle should be lower priority than touch boost.
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::NoVote, true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Min, true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Max, true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Heuristic, true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::ExplicitDefault, true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, true));
+
+    // With no layers, idle should still be lower priority than touch boost.
+    bool touchConsidered;
+    EXPECT_EQ(HWC_CONFIG_ID_90,
+              refreshRateConfigs
+                      ->getBestRefreshRate({}, /*touchActive=*/true, /*idle=*/true,
+                                           &touchConsidered)
+                      .getConfigId());
+
+    // Idle should be higher precedence than other layer frame rate considerations.
+    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::NoVote, false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Min, false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Max, false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Heuristic, false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::ExplicitDefault, false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, false));
+
+    // Idle should be applied rather than the current config when there are no layers.
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              refreshRateConfigs
+                      ->getBestRefreshRate({}, /*touchActive=*/false, /*idle=*/true,
+                                           &touchConsidered)
                       .getConfigId());
 }
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 229adb5..de66f8f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -30,6 +30,7 @@
 #include "mock/MockTimeStats.h"
 
 using namespace std::chrono_literals;
+using android::hardware::graphics::composer::hal::PowerMode;
 using testing::_;
 using testing::AtLeast;
 
@@ -50,10 +51,9 @@
     void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
         mRefreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
-        mRefreshRateStats =
-                std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
-                                                   /*currentConfigId=*/CONFIG_ID_0,
-                                                   /*currentPowerMode=*/HWC_POWER_MODE_OFF);
+        mRefreshRateStats = std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
+                                                               /*currentConfigId=*/CONFIG_ID_0,
+                                                               /*currentPowerMode=*/PowerMode::OFF);
     }
 
     Hwc2::mock::Display mDisplay;
@@ -111,7 +111,7 @@
     EXPECT_EQ(0u, times.count("90fps"));
 
     mRefreshRateStats->setConfigMode(CONFIG_ID_0);
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -119,7 +119,7 @@
     ASSERT_EQ(1u, times.count("90fps"));
     EXPECT_LT(0, times["90fps"]);
 
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+    mRefreshRateStats->setPowerMode(PowerMode::DOZE);
     int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -130,7 +130,7 @@
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+    // Because the power mode is not PowerMode::ON, switching the config
     // does not update refresh rates that come from the config.
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
@@ -158,7 +158,7 @@
     EXPECT_LT(screenOff, times["ScreenOff"]);
 
     mRefreshRateStats->setConfigMode(CONFIG_ID_0);
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -192,9 +192,9 @@
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_LT(sixty, times["60fps"]);
 
-    // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+    // Because the power mode is not PowerMode::ON, switching the config
     // does not update refresh rates that come from the config.
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+    mRefreshRateStats->setPowerMode(PowerMode::DOZE);
     mRefreshRateStats->setConfigMode(CONFIG_ID_0);
     sixty = mRefreshRateStats->getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index aa76613..445f04a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -212,7 +212,7 @@
         mFlinger->mRefreshRateStats = std::make_unique<
                 scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
                                              /*currentConfig=*/HwcConfigIndexType(0),
-                                             /*powerMode=*/HWC_POWER_MODE_OFF);
+                                             /*powerMode=*/hal::PowerMode::OFF);
         mFlinger->mPhaseConfiguration =
                 mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs);
 
@@ -319,7 +319,7 @@
 
     // Allow reading display state without locking, as if called on the SF main thread.
     auto setPowerModeInternal(const sp<DisplayDevice>& display,
-                              int mode) NO_THREAD_SAFETY_ANALYSIS {
+                              hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
@@ -328,11 +328,11 @@
     auto captureScreenImplLocked(const RenderArea& renderArea,
                                  SurfaceFlinger::TraverseLayersFunction traverseLayers,
                                  const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
-                                 bool forSystem, int* outSyncFd) {
+                                 bool forSystem, int* outSyncFd, bool regionSampling) {
         bool ignored;
         return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
                                                  useIdentityTransform, forSystem, outSyncFd,
-                                                 ignored);
+                                                 regionSampling, ignored);
     }
 
     auto traverseLayersInDisplay(const sp<const DisplayDevice>& display,
@@ -407,7 +407,6 @@
     auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
 
     auto fromHandle(const sp<IBinder>& handle) {
-        Mutex::Autolock _l(mFlinger->mStateLock);
         return mFlinger->fromHandle(handle);
     }
 
@@ -455,7 +454,7 @@
         static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
         static constexpr int32_t DEFAULT_DPI = 320;
         static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0;
-        static constexpr int32_t DEFAULT_POWER_MODE = 2;
+        static constexpr hal::PowerMode DEFAULT_POWER_MODE = hal::PowerMode::ON;
 
         FakeHwcDisplayInjector(DisplayId displayId, hal::DisplayType hwcDisplayType, bool isPrimary)
               : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
@@ -500,7 +499,7 @@
             return *this;
         }
 
-        auto& setPowerMode(int mode) {
+        auto& setPowerMode(hal::PowerMode mode) {
             mPowerMode = mode;
             return *this;
         }
@@ -525,7 +524,7 @@
             config.setConfigGroup(mConfigGroup);
             display->mutableConfigs().emplace(static_cast<int32_t>(mActiveConfig), config.build());
             display->mutableIsConnected() = true;
-            display->setPowerMode(static_cast<hal::PowerMode>(mPowerMode));
+            display->setPowerMode(mPowerMode);
 
             flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
 
@@ -549,7 +548,7 @@
         int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         int32_t mDpiY = DEFAULT_DPI;
         hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
-        int32_t mPowerMode = DEFAULT_POWER_MODE;
+        hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
         const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
     };
 
@@ -601,7 +600,7 @@
             return *this;
         }
 
-        auto& setPowerMode(int mode) {
+        auto& setPowerMode(hal::PowerMode mode) {
             mCreationArgs.initialPowerMode = mode;
             return *this;
         }
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 5de6bac..7a1c7c6 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -51,6 +51,8 @@
 using testing::StrEq;
 using testing::UnorderedElementsAre;
 
+using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
+
 // clang-format off
 #define FMT_PROTO          true
 #define FMT_STRING         false
@@ -394,7 +396,7 @@
 
 TEST_F(TimeStatsTest, canAverageFrameDuration) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats
             ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
                                   std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
@@ -423,7 +425,7 @@
                                                    .count());
 
     // Push a dummy present fence to trigger flushing the RenderEngine timings.
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
             std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
 
@@ -439,13 +441,13 @@
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
 
-    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
 
-    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::OFF));
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
     ASSERT_NO_FATAL_FAILURE(
@@ -463,12 +465,12 @@
 TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
-    mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
+    mTimeStats->setPowerMode(PowerMode::OFF);
     mTimeStats
             ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
                                   std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
                                           .count());
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats
             ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
                                   std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
@@ -504,7 +506,7 @@
     ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
 
     // Push a dummy present fence to trigger flushing the RenderEngine timings.
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
             std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
 
@@ -739,7 +741,7 @@
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
-    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
 
     mTimeStats
             ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
@@ -776,7 +778,7 @@
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats
             ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
                                   std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
@@ -894,7 +896,7 @@
     }
 
     mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->recordFrameDuration(1000000, 3000000);
     mTimeStats->recordRenderEngineDuration(2000000, 4000000);
     mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
@@ -1074,7 +1076,7 @@
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
 
     // Now make sure that TimeStats flushes global stats to set the callback.
-    mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
     EXPECT_THAT(mDelegate->mAtomTags,
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index fbbb69c..2a48a22 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -322,7 +322,7 @@
 TEST_F(TransactionApplicationTest, FromHandle) {
     sp<IBinder> badHandle;
     auto ret = mFlinger.fromHandle(badHandle);
-    EXPECT_EQ(nullptr, ret.get());
+    EXPECT_EQ(nullptr, ret.promote().get());
 }
 } // namespace android
 
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 32c9045..3f14d65 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -135,7 +135,7 @@
 
 class StubCallback : public DispSync::Callback {
 public:
-    void onDispSyncEvent(nsecs_t when) final {
+    void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
         std::lock_guard<std::mutex> lk(mMutex);
         mLastCallTime = when;
     }
@@ -544,7 +544,9 @@
     class SelfRemovingCallback : public DispSync::Callback {
     public:
         SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {}
-        void onDispSyncEvent(nsecs_t when) final { mVsr.removeEventListener(this, &when); }
+        void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
+            mVsr.removeEventListener(this, &when);
+        }
 
     private:
         VSyncReactor& mVsr;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
index 67d3e1c..dade9fc 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -84,15 +84,15 @@
     MOCK_METHOD2(validate, hal::Error(uint32_t*, uint32_t*));
     MOCK_METHOD4(presentOrValidate,
                  hal::Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
-    MOCK_CONST_METHOD1(setDisplayBrightness, hal::Error(float));
+    MOCK_METHOD1(setDisplayBrightness, std::future<hal::Error>(float));
     MOCK_CONST_METHOD1(getDisplayVsyncPeriod, hal::Error(nsecs_t*));
     MOCK_METHOD3(setActiveConfigWithConstraints,
                  hal::Error(const std::shared_ptr<const HWC2::Display::Config>&,
                             const hal::VsyncPeriodChangeConstraints&,
                             hal::VsyncPeriodChangeTimeline*));
-    MOCK_CONST_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
+    MOCK_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
     MOCK_CONST_METHOD1(getSupportedContentTypes, hal::Error(std::vector<hal::ContentType>*));
-    MOCK_CONST_METHOD1(setContentType, hal::Error(hal::ContentType));
+    MOCK_METHOD1(setContentType, hal::Error(hal::ContentType));
     MOCK_CONST_METHOD1(getConnectionType, hal::Error(android::DisplayConnectionType*));
     MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool());
 };
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
index f6c4f62..1c8c44d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -17,6 +17,7 @@
 #include "mock/MockDispSync.h"
 #include <thread>
 
+using namespace std::chrono_literals;
 namespace android {
 namespace mock {
 
@@ -54,8 +55,9 @@
 void DispSync::triggerCallback() {
     if (mCallback.callback == nullptr) return;
 
-    mCallback.callback->onDispSyncEvent(
-            std::chrono::steady_clock::now().time_since_epoch().count());
+    const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch();
+    const auto expectedVSyncTime = now + 16ms;
+    mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count());
 }
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
index 97a13e4..5fb06fd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
@@ -16,12 +16,15 @@
 
 #include "mock/MockMessageQueue.h"
 
-namespace android {
-namespace mock {
+namespace android::mock {
 
-// Explicit default instantiation is recommended.
-MessageQueue::MessageQueue() = default;
+MessageQueue::MessageQueue() {
+    ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
+        // Execute task to prevent broken promise exception on destruction.
+        handler->handleMessage(Message());
+    });
+}
+
 MessageQueue::~MessageQueue() = default;
 
-} // namespace mock
-} // namespace android
\ No newline at end of file
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index e781c0a..a82b583 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -21,8 +21,7 @@
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
 
-namespace android {
-namespace mock {
+namespace android::mock {
 
 class MessageQueue : public android::MessageQueue {
 public:
@@ -32,10 +31,9 @@
     MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
     MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
     MOCK_METHOD0(waitMessage, void());
-    MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
+    MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
     MOCK_METHOD0(invalidate, void());
     MOCK_METHOD0(refresh, void());
 };
 
-} // namespace mock
-} // namespace android
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index dca1070..4186e2b 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -53,7 +53,8 @@
     MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
     MOCK_METHOD1(onDestroy, void(int32_t));
     MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
-    MOCK_METHOD1(setPowerMode, void(int32_t));
+    MOCK_METHOD1(setPowerMode,
+                 void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
     MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
     MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
 };
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index dcaa663..9cf4905 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -14,6 +14,7 @@
 ]
 
 header_libraries = [
+    "jni_headers",
     "libdvr_headers",
 ]
 
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 018f200..f69de1f 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -79,6 +79,7 @@
         "hwvulkan_headers",
         "libnativeloader-headers",
         "vulkan_headers",
+        "libsurfaceflinger_headers",
     ],
     export_header_lib_headers: ["vulkan_headers"],
     shared_libs: [
@@ -100,6 +101,7 @@
         "libnativeloader_lazy",
         "libnativewindow",
         "android.hardware.graphics.common@1.0",
+        "libSurfaceFlingerProp",
     ],
     static_libs: ["libgrallocusage"],
 }
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a7ec4ae..22122a5 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -23,9 +23,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <SurfaceFlingerProperties.h>
+#include <android-base/properties.h>
 #include <android/dlext.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <android-base/properties.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
@@ -160,7 +161,7 @@
 }
 
 const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
-    "ro.hardware." HWVULKAN_HARDWARE_MODULE_ID,
+    "ro.hardware.vulkan",
     "ro.board.platform",
 }};
 
@@ -959,9 +960,7 @@
         VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
         VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
 
-    bool hdrBoardConfig =
-        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(
-            false);
+    bool hdrBoardConfig = android::sysprop::has_HDR_display(false);
     if (hdrBoardConfig) {
         loader_extensions.push_back({VK_EXT_HDR_METADATA_EXTENSION_NAME,
                                      VK_EXT_HDR_METADATA_SPEC_VERSION});
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a44b9e7..d3ed88d 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1478,7 +1478,7 @@
     ANativeWindowBuffer* buffer;
     int fence_fd;
     err = window->dequeueBuffer(window, &buffer, &fence_fd);
-    if (err == android::TIMED_OUT) {
+    if (err == android::TIMED_OUT || err == android::INVALID_OPERATION) {
         ALOGW("dequeueBuffer timed out: %s (%d)", strerror(-err), err);
         return timeout ? VK_TIMEOUT : VK_NOT_READY;
     } else if (err != android::OK) {