Merge "SurfaceFlinger: Layer::getFrameRate() with relatives" into rvc-dev
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 466575f..a0b9cbb 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -84,7 +84,8 @@
                                                 android::base::unique_fd bugreport_fd,
                                                 android::base::unique_fd screenshot_fd,
                                                 int bugreport_mode,
-                                                const sp<IDumpstateListener>& listener) {
+                                                const sp<IDumpstateListener>& listener,
+                                                bool is_screenshot_requested) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
     // Ensure there is only one bugreport in progress at a time.
@@ -118,7 +119,7 @@
 
     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
     options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
-                        screenshot_fd);
+                        screenshot_fd, is_screenshot_requested);
 
     if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) {
         MYLOGE("Invalid filedescriptor");
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 6dc0225..ac8d3ac 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -41,7 +41,8 @@
     binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
                                   android::base::unique_fd bugreport_fd,
                                   android::base::unique_fd screenshot_fd, int bugreport_mode,
-                                  const sp<IDumpstateListener>& listener) override;
+                                  const sp<IDumpstateListener>& listener,
+                                  bool is_screenshot_requested) override;
 
     // No-op
     binder::Status cancelBugreport();
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 3f359c8..ba008bb 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -64,10 +64,12 @@
      * @param screenshotFd the file to which screenshot should be written
      * @param bugreportMode the mode that specifies other run time options; must be one of above
      * @param listener callback for updates; optional
+     * @param isScreenshotRequested indicates screenshot is requested or not
      */
     void startBugreport(int callingUid, @utf8InCpp String callingPackage,
                         FileDescriptor bugreportFd, FileDescriptor screenshotFd,
-                        int bugreportMode, IDumpstateListener listener);
+                        int bugreportMode, IDumpstateListener listener,
+                        boolean isScreenshotRequested);
 
     /*
      * Cancels the bugreport currently in progress.
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3440116..ec2b922 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1477,6 +1477,8 @@
         ds.AddDir(WMTRACE_DATA_DIR, false);
     }
 
+    ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
+
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
 
     /* Migrate the ril_dumpstate to a device specific dumpstate? */
@@ -1605,7 +1607,6 @@
     ds.AddDir(RECOVERY_DATA_DIR, true);
     ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
     ds.AddDir(LOGPERSIST_DATA_DIR, false);
-    ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
     if (!PropertiesHelper::IsUserBuild()) {
         ds.AddDir(PROFILE_DATA_DIR_CUR, true);
         ds.AddDir(PROFILE_DATA_DIR_REF, true);
@@ -1728,6 +1729,8 @@
     RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"telephony.registry"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
     if (include_sensitive_info) {
         // Contains raw IP addresses, omit from reports on user builds.
         RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
@@ -2246,20 +2249,21 @@
     }
 }
 
-static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
+static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options,
+                               bool is_screenshot_requested) {
     // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for
     // default system screenshots.
     options->bugreport_mode = ModeToString(mode);
     switch (mode) {
         case Dumpstate::BugreportMode::BUGREPORT_FULL:
-            options->do_screenshot = true;
+            options->do_screenshot = is_screenshot_requested;
             options->dumpstate_hal_mode = DumpstateMode::FULL;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
             // Currently, the dumpstate binder is only used by Shell to update progress.
             options->do_start_service = true;
             options->do_progress_updates = true;
-            options->do_screenshot = true;
+            options->do_screenshot = is_screenshot_requested;
             options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
@@ -2272,7 +2276,7 @@
             options->do_start_service = true;
             options->do_progress_updates = true;
             options->do_zip_file = true;
-            options->do_screenshot = true;
+            options->do_screenshot = is_screenshot_requested;
             options->dumpstate_hal_mode = DumpstateMode::WEAR;
             break;
         // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
@@ -2309,7 +2313,8 @@
 
 void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
                                         const android::base::unique_fd& bugreport_fd_in,
-                                        const android::base::unique_fd& screenshot_fd_in) {
+                                        const android::base::unique_fd& screenshot_fd_in,
+                                        bool is_screenshot_requested) {
     // In the new API world, date is always added; output is always a zip file.
     // TODO(111441001): remove these options once they are obsolete.
     do_add_date = true;
@@ -2319,7 +2324,7 @@
     bugreport_fd.reset(dup(bugreport_fd_in.get()));
     screenshot_fd.reset(dup(screenshot_fd_in.get()));
 
-    SetOptionsFromMode(bugreport_mode, this);
+    SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
 }
 
 Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7e27787..7b8d282 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -390,7 +390,8 @@
 
         /* Initializes options from the requested mode. */
         void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd,
-                        const android::base::unique_fd& screenshot_fd);
+                        const android::base::unique_fd& screenshot_fd,
+                        bool is_screenshot_requested);
 
         /* Returns true if the options set so far are consistent. */
         bool ValidateOptions() const;
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index f26e4db..047a1c3 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -451,7 +451,7 @@
     sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
     android::binder::Status status =
         ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
-                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener, true);
     // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
     // gets expected callbacks.
     EXPECT_TRUE(status.isOk());
@@ -488,7 +488,7 @@
     android::binder::Status status =
         ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
                                   2000,  // invalid bugreport mode
-                                  listener);
+                                  listener, false);
     EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
 
     // The service should have died, freeing itself up for a new invocation.
@@ -519,13 +519,13 @@
     sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
     android::binder::Status status =
         ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
-                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1, true);
     EXPECT_TRUE(status.isOk());
 
     // try to make another call to startBugreport. This should fail.
     sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
     status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2),
-                                       Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
+                                       Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2, true);
     EXPECT_FALSE(status.isOk());
     WaitTillExecutionComplete(listener2.get());
     EXPECT_EQ(listener2->getErrorCode(),
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 0a0c40e..2efb130 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -233,7 +233,7 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
-    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_screenshot);
     EXPECT_TRUE(options_.do_zip_file);
@@ -250,7 +250,7 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
-    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
@@ -267,7 +267,7 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
-    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.is_remote_mode);
@@ -283,7 +283,7 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeWearBugReport) {
-    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_screenshot);
     EXPECT_TRUE(options_.do_zip_file);
@@ -300,7 +300,7 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
-    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_TRUE(options_.do_zip_file);
@@ -317,7 +317,7 @@
 }
 
 TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
-    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd);
+    options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_TRUE(options_.do_zip_file);
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index f426dbb..fb11cee 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -406,7 +406,7 @@
         return false;
     }
 
-    if (fqInstance.getPackage() == gIBaseFqName.package()) {
+    if (fqInstance.getPackage() == "android.hidl.base") {
         return true; // always remove IBase from manifest
     }
 
diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h
deleted file mode 120000
index c2047c0..0000000
--- a/include/ui/FatVector.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/ui/include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index aeca12b..2174ce2 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -30,24 +30,10 @@
 
 namespace android {
 
-namespace {
-
-#if defined(__BRILLO__)
-// Because Brillo has no application model, security policy is managed
-// statically (at build time) with SELinux controls.
-// As a consequence, it also never runs the AppOpsManager service.
-const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED;
-#else
-const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
-#endif  // defined(__BRILLO__)
-
-}  // namespace
-
-static String16 _appops("appops");
-static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER;
-static sp<IBinder> gClientId;
-
 static const sp<IBinder>& getClientId() {
+    static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER;
+    static sp<IBinder> gClientId;
+
     pthread_mutex_lock(&gClientIdMutex);
     if (gClientId == nullptr) {
         gClientId = new BBinder();
@@ -56,22 +42,13 @@
     return gClientId;
 }
 
-thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
-thread_local int32_t uidOfThisBinderTransaction = -1;
-
-// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
-uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
-
 AppOpsManager::AppOpsManager()
 {
 }
 
-#if defined(__BRILLO__)
-// There is no AppOpsService on Brillo
-sp<IAppOpsService> AppOpsManager::getService() { return NULL; }
-#else
 sp<IAppOpsService> AppOpsManager::getService()
 {
+    static String16 _appops("appops");
 
     std::lock_guard<Mutex> scoped_lock(mLock);
     int64_t startTime = 0;
@@ -96,14 +73,13 @@
     }
     return service;
 }
-#endif  // defined(__BRILLO__)
 
 int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
 {
     sp<IAppOpsService> service = getService();
     return service != nullptr
             ? service->checkOperation(op, uid, callingPackage)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            : AppOpsManager::MODE_IGNORED;
 }
 
 int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
@@ -111,7 +87,7 @@
     sp<IAppOpsService> service = getService();
     return service != nullptr
            ? service->checkAudioOperation(op, usage, uid, callingPackage)
-           : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+           : AppOpsManager::MODE_IGNORED;
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -120,12 +96,12 @@
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
-        const std::unique_ptr<String16>& featureId, const String16& message) {
+        const std::unique_ptr<String16>& attributionTag, const String16& message) {
     sp<IAppOpsService> service = getService();
     int32_t mode = service != nullptr
-            ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op),
-                    message)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            ? service->noteOperation(op, uid, callingPackage, attributionTag,
+                    shouldCollectNotes(op), message)
+            : AppOpsManager::MODE_IGNORED;
 
     return mode;
 }
@@ -137,13 +113,13 @@
 }
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
-        bool startIfModeDefault, const std::unique_ptr<String16>& featureId,
+        bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag,
         const String16& message) {
     sp<IAppOpsService> service = getService();
     int32_t mode = service != nullptr
             ? service->startOperation(getClientId(), op, uid, callingPackage,
-                    featureId, startIfModeDefault, shouldCollectNotes(op), message)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+                    attributionTag, startIfModeDefault, shouldCollectNotes(op), message)
+            : AppOpsManager::MODE_IGNORED;
 
     return mode;
 }
@@ -153,10 +129,10 @@
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage,
-        const std::unique_ptr<String16>& callingFeatureId) {
+        const std::unique_ptr<String16>& attributionTag) {
     sp<IAppOpsService> service = getService();
     if (service != nullptr) {
-        service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId);
+        service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag);
     }
 }
 
@@ -192,6 +168,9 @@
 
 // check it the appops needs to be collected and cache result
 bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
+    // Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
+    static uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
+
     if (appOpsToNote[opcode] == 0) {
         if (getService()->shouldCollectNotes(opcode)) {
             appOpsToNote[opcode] = 2;
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 2f6e9c3..e0fb543 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -141,7 +141,7 @@
 
 // ---------------------------------------------------------------------------
 
-BBinder::BBinder() : mExtras(nullptr)
+BBinder::BBinder() : mExtras(nullptr), mStability(0)
 {
 }
 
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index f16c39c..d2b9b8f 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -138,6 +138,7 @@
 
 BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
     : mHandle(handle)
+    , mStability(0)
     , mAlive(1)
     , mObitsSent(0)
     , mObituaries(nullptr)
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index a5555a3..0714723 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -47,14 +47,14 @@
     }
 
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
-                const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp,
+                const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
                 const String16& message) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
-        data.writeString16(featureId);
+        data.writeString16(attributionTag);
         data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0);
         data.writeString16(message);
         remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply);
@@ -64,7 +64,7 @@
     }
 
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName, const std::unique_ptr<String16>& featureId,
+                const String16& packageName, const std::unique_ptr<String16>& attributionTag,
                 bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -72,7 +72,7 @@
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
-        data.writeString16(featureId);
+        data.writeString16(attributionTag);
         data.writeInt32(startIfModeDefault ? 1 : 0);
         data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0);
         data.writeString16(message);
@@ -83,14 +83,14 @@
     }
 
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::unique_ptr<String16>& featureId) {
+            const String16& packageName, const std::unique_ptr<String16>& attributionTag) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
-        data.writeString16(featureId);
+        data.writeString16(attributionTag);
         remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply);
     }
 
@@ -182,11 +182,11 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            std::unique_ptr<String16> featureId;
-            data.readString16(&featureId);
+            std::unique_ptr<String16> attributionTag;
+            data.readString16(&attributionTag);
             bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
             String16 message = data.readString16();
-            int32_t res = noteOperation(code, uid, packageName, featureId,
+            int32_t res = noteOperation(code, uid, packageName, attributionTag,
                     shouldCollectAsyncNotedOp, message);
             reply->writeNoException();
             reply->writeInt32(res);
@@ -198,12 +198,12 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            std::unique_ptr<String16> featureId;
-            data.readString16(&featureId);
+            std::unique_ptr<String16> attributionTag;
+            data.readString16(&attributionTag);
             bool startIfModeDefault = data.readInt32() == 1;
             bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
             String16 message = data.readString16();
-            int32_t res = startOperation(token, code, uid, packageName, featureId,
+            int32_t res = startOperation(token, code, uid, packageName, attributionTag,
                     startIfModeDefault, shouldCollectAsyncNotedOp, message);
             reply->writeNoException();
             reply->writeInt32(res);
@@ -215,9 +215,9 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            std::unique_ptr<String16> featureId;
-            data.readString16(&featureId);
-            finishOperation(token, code, uid, packageName, featureId);
+            std::unique_ptr<String16> attributionTag;
+            data.readString16(&attributionTag);
+            finishOperation(token, code, uid, packageName, attributionTag);
             reply->writeNoException();
             return NO_ERROR;
         } break;
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 7ce5e36..e1565fa 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -15,6 +15,9 @@
  */
 #include <binder/Stability.h>
 
+#include <binder/BpBinder.h>
+#include <binder/Binder.h>
+
 namespace android {
 namespace internal {
 
@@ -78,11 +81,12 @@
 
     if (currentStability == stability) return OK;
 
-    binder->attachObject(
-        reinterpret_cast<void*>(&Stability::get),
-        reinterpret_cast<void*>(stability),
-        nullptr /*cleanupCookie*/,
-        nullptr /*cleanup function*/);
+    BBinder* local = binder->localBinder();
+    if (local != nullptr) {
+        local->mStability = static_cast<int32_t>(stability);
+    } else {
+        binder->remoteBinder()->mStability = static_cast<int32_t>(stability);
+    }
 
     return OK;
 }
@@ -90,8 +94,12 @@
 Stability::Level Stability::get(IBinder* binder) {
     if (binder == nullptr) return UNDECLARED;
 
-    return static_cast<Level>(reinterpret_cast<intptr_t>(
-        binder->findObject(reinterpret_cast<void*>(&Stability::get))));
+    BBinder* local = binder->localBinder();
+    if (local != nullptr) {
+        return static_cast<Stability::Level>(local->mStability);
+    }
+
+    return static_cast<Stability::Level>(binder->remoteBinder()->mStability);
 }
 
 bool Stability::check(int32_t provided, Level required) {
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 5b6eb68..2ee5930 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -134,18 +134,18 @@
     //              const String16&) instead
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
-            const std::unique_ptr<String16>& featureId, const String16& message);
+            const std::unique_ptr<String16>& attributionTag, const String16& message);
     // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&,
     //              const String16&) instead
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
             bool startIfModeDefault);
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
-            bool startIfModeDefault, const std::unique_ptr<String16>& featureId,
+            bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag,
             const String16& message);
     // @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage,
-            const std::unique_ptr<String16>& featureId);
+            const std::unique_ptr<String16>& attributionTag);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
     void stopWatchingMode(const sp<IAppOpsCallback>& callback);
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 3be61f9..74e52db 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -24,6 +24,10 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+namespace internal {
+class Stability;
+}
+
 class BBinder : public IBinder
 {
 public:
@@ -88,7 +92,12 @@
     Extras*             getOrCreateExtras();
 
     std::atomic<Extras*> mExtras;
-            void*       mReserved0;
+
+    friend ::android::internal::Stability;
+    union {
+        int32_t mStability;
+        void* mReserved0;
+    };
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 7dca733..8e871b8 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -27,6 +27,10 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+namespace internal {
+class Stability;
+};
+
 using binder_proxy_limit_callback = void(*)(int);
 
 class BpBinder : public IBinder
@@ -116,6 +120,9 @@
 private:
     const   int32_t             mHandle;
 
+    friend ::android::internal::Stability;
+            int32_t             mStability;
+
     struct Obituary {
         wp<DeathRecipient> recipient;
         void* cookie;
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 1b4bcce..1ffb8de 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -36,13 +36,13 @@
 
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
-            const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp,
+            const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
             const String16& message) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::unique_ptr<String16>& featureId,
+            const String16& packageName, const std::unique_ptr<String16>& attributionTag,
             bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0;
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::unique_ptr<String16>& featureId) = 0;
+            const String16& packageName, const std::unique_ptr<String16>& attributionTag) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback) = 0;
     virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h
new file mode 100644
index 0000000..b605bd3
--- /dev/null
+++ b/libs/binder/include/binder/Nullable.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+#include <utility>
+
+namespace android {
+
+namespace aidl {
+
+// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr
+// usage:
+//     nullable<Foo> a;
+//     nullable<Foo> b = make_nullable<Foo>(...);
+//     auto c = make_nullable<Foo>(...);
+//     c.reset();
+//     c = make_nullable<Foo>(...);
+//     c = std::move(a);
+
+template <typename T>
+using nullable = std::unique_ptr<T>;
+
+template <typename T, typename... Args>
+inline nullable<T> make_nullable(Args&&... args) {
+    return std::make_unique<T>(std::forward<Args>(args)...);
+}
+
+} // namespace aidl
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 75dcdc8..649faa1 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -486,7 +486,6 @@
 
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
-        LOG(ERROR) << __func__ << ": on null binder";
         return;
     }
 
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 1b42b69..5b65c95 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -57,6 +57,7 @@
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
         "android.hardware.biometrics.face@1.0::IBiometricsFace",
+        "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
         "android.hardware.bluetooth@1.0::IBluetoothHci",
         "android.hardware.camera.provider@2.4::ICameraProvider",
         "android.hardware.drm@1.0::IDrmFactory",
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index befabee..4809c1f 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -61,26 +61,25 @@
     VNDKSP = 1,
 };
 
-static constexpr const char* kNativeLibrariesSystemConfigPath[] = {"/etc/llndk.libraries.txt",
-                                                                   "/etc/vndksp.libraries.txt"};
+static constexpr const char* kNativeLibrariesSystemConfigPath[] =
+        {"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt",
+         "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"};
 
 static std::string vndkVersionStr() {
 #ifdef __BIONIC__
-    std::string version = android::base::GetProperty("ro.vndk.version", "");
-    if (version != "" && version != "current") {
-        return "." + version;
-    }
+    return android::base::GetProperty("ro.vndk.version", "");
 #endif
     return "";
 }
 
 static void insertVndkVersionStr(std::string* fileName) {
     LOG_ALWAYS_FATAL_IF(!fileName, "fileName should never be nullptr");
-    size_t insertPos = fileName->find_last_of(".");
-    if (insertPos == std::string::npos) {
-        insertPos = fileName->length();
+    std::string version = vndkVersionStr();
+    size_t pos = fileName->find("{}");
+    while (pos != std::string::npos) {
+        fileName->replace(pos, 2, version);
+        pos = fileName->find("{}", pos + version.size());
     }
-    fileName->insert(insertPos, vndkVersionStr());
 }
 
 static bool readConfig(const std::string& configFile, std::vector<std::string>* soNames) {
@@ -103,11 +102,7 @@
 }
 
 static const std::string getSystemNativeLibraries(NativeLibrary type) {
-    static const char* androidRootEnv = getenv("ANDROID_ROOT");
-    static const std::string rootDir = androidRootEnv != nullptr ? androidRootEnv : "/system";
-
-    std::string nativeLibrariesSystemConfig = rootDir + kNativeLibrariesSystemConfigPath[type];
-
+    std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
     insertVndkVersionStr(&nativeLibrariesSystemConfig);
 
     std::vector<std::string> soNames;
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
index 0ddb87e..b5cdeb2 100644
--- a/libs/gui/BufferHubConsumer.cpp
+++ b/libs/gui/BufferHubConsumer.cpp
@@ -147,16 +147,6 @@
     return INVALID_OPERATION;
 }
 
-status_t BufferHubConsumer::setFrameRate(float /*frameRate*/) {
-    ALOGE("BufferHubConsumer::setFrameRate: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::getFrameRate(float* /*frameRate*/) const {
-    ALOGE("BufferHubConsumer::getFrameRate: not implemented.");
-    return INVALID_OPERATION;
-}
-
 status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
     ALOGE("BufferHubConsumer::dumpState: not implemented.");
     return INVALID_OPERATION;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 4435265..da6143c 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -783,18 +783,6 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueConsumer::setFrameRate(float frameRate) {
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
-    mCore->mFrameRate = frameRate;
-    return NO_ERROR;
-}
-
-status_t BufferQueueConsumer::getFrameRate(float* frameRate) const {
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
-    *frameRate = mCore->mFrameRate;
-    return NO_ERROR;
-}
-
 status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const {
     struct passwd* pwd = getpwnam("shell");
     uid_t shellUid = pwd ? pwd->pw_uid : 0;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 9e5d681..a1803d8 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -130,8 +130,7 @@
         mLastQueuedSlot(INVALID_BUFFER_SLOT),
         mUniqueId(getUniqueId()),
         mAutoPrerotation(false),
-        mTransformHintInUse(0),
-        mFrameRate(0) {
+        mTransformHintInUse(0) {
     int numStartingBuffers = getMaxBufferCountLocked();
     for (int s = 0; s < numStartingBuffers; s++) {
         mFreeSlots.insert(s);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9e86838..3f4c5da 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1676,14 +1676,4 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueProducer::setFrameRate(float frameRate) {
-    ATRACE_CALL();
-    BQ_LOGV("setFrameRate: %.0f", frameRate);
-
-    std::lock_guard<std::mutex> lock(mCore->mMutex);
-
-    mCore->mFrameRate = frameRate;
-    return NO_ERROR;
-}
-
 } // namespace android
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 515f45c..9f91d9d 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -363,24 +363,6 @@
     return OK;
 }
 
-status_t ConsumerBase::setFrameRate(float frameRate) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CB_LOGE("setFrameRate: ConsumerBase is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setFrameRate(frameRate);
-}
-
-status_t ConsumerBase::getFrameRate(float* frameRate) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CB_LOGE("getFrameRate: ConsumerBase is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->getFrameRate(frameRate);
-}
-
 void ConsumerBase::dumpState(String8& result) const {
     dumpState(result, "");
 }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 2521a7c..c705d39 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -51,8 +51,6 @@
     GET_SIDEBAND_STREAM,
     GET_OCCUPANCY_HISTORY,
     DISCARD_FREE_BUFFERS,
-    SET_FRAME_RATE,
-    GET_FRAME_RATE,
     DUMP_STATE,
     LAST = DUMP_STATE,
 };
@@ -165,16 +163,6 @@
                 Tag::DISCARD_FREE_BUFFERS);
     }
 
-    status_t setFrameRate(float frameRate) override {
-        using Signature = decltype(&IGraphicBufferConsumer::setFrameRate);
-        return callRemote<Signature>(Tag::SET_FRAME_RATE, frameRate);
-    }
-
-    status_t getFrameRate(float* frameRate) const override {
-        using Signature = decltype(&IGraphicBufferConsumer::getFrameRate);
-        return callRemote<Signature>(Tag::GET_FRAME_RATE, frameRate);
-    }
-
     status_t dumpState(const String8& prefix, String8* outResult) const override {
         using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
         return callRemote<Signature>(Tag::DUMP_STATE, prefix, outResult);
@@ -232,10 +220,6 @@
             return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory);
         case Tag::DISCARD_FREE_BUFFERS:
             return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers);
-        case Tag::SET_FRAME_RATE:
-            return callLocal(data, reply, &IGraphicBufferConsumer::setFrameRate);
-        case Tag::GET_FRAME_RATE:
-            return callLocal(data, reply, &IGraphicBufferConsumer::getFrameRate);
         case Tag::DUMP_STATE: {
             using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const;
             return callLocal<Signature>(data, reply, &IGraphicBufferConsumer::dumpState);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 7b5596e..ad00939 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -74,7 +74,6 @@
     GET_CONSUMER_USAGE,
     SET_LEGACY_BUFFER_DROP,
     SET_AUTO_PREROTATION,
-    SET_FRAME_RATE,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -560,14 +559,6 @@
         }
         return result;
     }
-
-    virtual status_t setFrameRate(float frameRate) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeFloat(frameRate);
-        status_t result = remote()->transact(SET_FRAME_RATE, data, &reply, IBinder::FLAG_ONEWAY);
-        return result;
-    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -700,8 +691,6 @@
     status_t setAutoPrerotation(bool autoPrerotation) override {
         return mBase->setAutoPrerotation(autoPrerotation);
     }
-
-    status_t setFrameRate(float frameRate) override { return mBase->setFrameRate(frameRate); }
 };
 
 IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
@@ -721,12 +710,6 @@
     return INVALID_OPERATION;
 }
 
-status_t IGraphicBufferProducer::setFrameRate(float frameRate) {
-    // No-op for IGBP other than BufferQueue.
-    (void)frameRate;
-    return INVALID_OPERATION;
-}
-
 status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
     status_t res = OK;
     res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1096,13 +1079,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_FRAME_RATE: {
-            CHECK_INTERFACE(IGraphicBuffer, data, reply);
-            float frameRate = data.readFloat();
-            status_t result = setFrameRate(frameRate);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 915ebf9..8d79cf8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1280,6 +1280,9 @@
 
             std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
             int numExcludeHandles = data.readInt32();
+            if (numExcludeHandles >= static_cast<int>(MAX_LAYERS)) {
+                return BAD_VALUE;
+            }
             excludeHandles.reserve(numExcludeHandles);
             for (int i = 0; i < numExcludeHandles; i++) {
                 excludeHandles.emplace(data.readStrongBinder());
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index a9c9b74..f7158d0 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -443,39 +443,18 @@
 // ------------------------------- InputWindowCommands ----------------------------------------
 
 void InputWindowCommands::merge(const InputWindowCommands& other) {
-    transferTouchFocusCommands
-            .insert(transferTouchFocusCommands.end(),
-                    std::make_move_iterator(other.transferTouchFocusCommands.begin()),
-                    std::make_move_iterator(other.transferTouchFocusCommands.end()));
-
     syncInputWindows |= other.syncInputWindows;
 }
 
 void InputWindowCommands::clear() {
-    transferTouchFocusCommands.clear();
     syncInputWindows = false;
 }
 
 void InputWindowCommands::write(Parcel& output) const {
-    output.writeUint32(static_cast<uint32_t>(transferTouchFocusCommands.size()));
-    for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) {
-        output.writeStrongBinder(transferTouchFocusCommand.fromToken);
-        output.writeStrongBinder(transferTouchFocusCommand.toToken);
-    }
-
     output.writeBool(syncInputWindows);
 }
 
 void InputWindowCommands::read(const Parcel& input) {
-    size_t count = input.readUint32();
-    transferTouchFocusCommands.clear();
-    for (size_t i = 0; i < count; i++) {
-        TransferTouchFocusCommand transferTouchFocusCommand;
-        transferTouchFocusCommand.fromToken = input.readStrongBinder();
-        transferTouchFocusCommand.toToken = input.readStrongBinder();
-        transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
-    }
-
     syncInputWindows = input.readBool();
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index dc4860a..2307fbf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1290,15 +1290,6 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus(
-        const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
-    InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand;
-    transferTouchFocusCommand.fromToken = fromToken;
-    transferTouchFocusCommand.toToken = toToken;
-    mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
-    return *this;
-}
-
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
     mInputWindowCommands.syncInputWindows = true;
     return *this;
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
index d756203..d380770 100644
--- a/libs/gui/include/gui/BufferHubConsumer.h
+++ b/libs/gui/include/gui/BufferHubConsumer.h
@@ -93,12 +93,6 @@
     // See |IGraphicBufferConsumer::discardFreeBuffers|
     status_t discardFreeBuffers() override;
 
-    // See |IGraphicBufferConsumer::setFrameRate|
-    status_t setFrameRate(float frameRate) override;
-
-    // See |IGraphicBufferConsumer::getFrameRate|
-    status_t getFrameRate(float* frameRate) const override;
-
     // See |IGraphicBufferConsumer::dumpState|
     status_t dumpState(const String8& prefix, String8* outResult) const override;
 
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index e9f0449..7db69ec 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -149,12 +149,6 @@
     // See IGraphicBufferConsumer::discardFreeBuffers
     virtual status_t discardFreeBuffers() override;
 
-    // See IGraphicBufferConsumer::setFrameRate.
-    virtual status_t setFrameRate(float frameRate) override;
-
-    // See IGraphicBufferConsumer::getFrameRate.
-    virtual status_t getFrameRate(float* frameRate) const override;
-
     // dump our state in a String
     status_t dumpState(const String8& prefix, String8* outResult) const override;
 
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 05c2074..557c28b 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -354,9 +354,6 @@
     // mTransformHintInUse is to cache the mTransformHint used by the producer.
     uint32_t mTransformHintInUse;
 
-    // The frame rate the app intends to run at.
-    float mFrameRate;
-
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index cbace5b..a7f7d1d 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -198,9 +198,6 @@
     // See IGraphicBufferProducer::setAutoPrerotation
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
-    // See IGraphicBufferProducer::setFrameRate
-    virtual status_t setFrameRate(float frameRate) override;
-
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index cfed9aa..8ff0cd0 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -111,12 +111,6 @@
     // See IGraphicBufferConsumer::discardFreeBuffers
     status_t discardFreeBuffers();
 
-    // See IGraphicBufferConsumer::setFrameRate
-    status_t setFrameRate(float frameRate);
-
-    // See IGraphicBufferConsumer::getFrameRate
-    status_t getFrameRate(float* frameRate);
-
 private:
     ConsumerBase(const ConsumerBase&);
     void operator=(const ConsumerBase&);
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 56fe949..0b92e7d 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -275,16 +275,6 @@
     // call to free up any of its locally cached buffers.
     virtual status_t discardFreeBuffers() = 0;
 
-    // Set the frame rate the producer will run at.
-    //
-    // Return of a value other than NO_ERROR means an unknown error has occurred.
-    virtual status_t setFrameRate(float frameRate) = 0;
-
-    // Get the frame rate the producer will run at.
-    //
-    // Return of a value other than NO_ERROR means an unknown error has occurred.
-    virtual status_t getFrameRate(float* frameRate) const = 0;
-
     // dump state into a string
     virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0;
 
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 87989da..d7f3492 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -639,9 +639,6 @@
     // the width and height used for dequeueBuffer will be additionally swapped.
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
-    // Sets the apps intended frame rate.
-    virtual status_t setFrameRate(float frameRate);
-
 #ifndef NO_BINDER
     // Static method exports any IGraphicBufferProducer object to a parcel. It
     // handles null producer as well.
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0659f0d..09487ea 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -76,6 +76,8 @@
 public:
     DECLARE_META_INTERFACE(SurfaceComposer)
 
+    static constexpr size_t MAX_LAYERS = 4096;
+
     // flags for setTransactionState()
     enum {
         eSynchronous = 0x01,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 7e3d5d5..2b2f773 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -271,12 +271,6 @@
 };
 
 struct InputWindowCommands {
-    struct TransferTouchFocusCommand {
-        sp<IBinder> fromToken;
-        sp<IBinder> toToken;
-    };
-
-    std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
     bool syncInputWindows{false};
 
     void merge(const InputWindowCommands& other);
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index ad7cbfe..917c0d4 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -178,7 +178,6 @@
     status_t getUniqueId(uint64_t* outId) const;
     status_t getConsumerUsage(uint64_t* outUsage) const;
 
-    // See IGraphicBufferProducer::setFrameRate
     status_t setFrameRate(float frameRate, int8_t compatibility);
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0cf141d..2fb9538 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -507,7 +507,6 @@
 
 #ifndef NO_INPUT
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
-        Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
         Transaction& syncInputWindows();
 #endif
 
diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
index e940cf3..98f24c2 100644
--- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h
+++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
@@ -49,8 +49,6 @@
     MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
     MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
     MOCK_METHOD0(discardFreeBuffers, status_t());
-    MOCK_METHOD1(setFrameRate, status_t(float));
-    MOCK_CONST_METHOD1(getFrameRate, status_t(float*));
     MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
 };
 
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 0f7e2fb..0ff33ac 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -185,9 +185,18 @@
 }
 
 void Choreographer::scheduleCallbacks() {
-    AutoMutex _{mLock};
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (mFrameCallbacks.top().dueTime <= now) {
+    const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t dueTime;
+    {
+        AutoMutex _{mLock};
+        // If there are no pending callbacks then don't schedule a vsync
+        if (mFrameCallbacks.empty()) {
+            return;
+        }
+        dueTime = mFrameCallbacks.top().dueTime;
+    }
+
+    if (dueTime <= now) {
         ALOGV("choreographer %p ~ scheduling vsync", this);
         scheduleVsync();
         return;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 416ebfe..e73f245 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -381,15 +381,6 @@
         LOG_ALWAYS_FATAL_IF(!success, "can't make default context current");
     }
 
-    const uint16_t protTexData[] = {0};
-    glGenTextures(1, &mProtectedTexName);
-    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
-
     // mColorBlindnessCorrection = M;
 
     if (mUseColorManagement) {
@@ -966,9 +957,13 @@
         return NO_ERROR;
     }
 
-    if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
-        ATRACE_NAME("Waiting before draw");
-        sync_wait(bufferFence.get(), -1);
+    if (bufferFence.get() >= 0) {
+        // Duplicate the fence for passing to waitFence.
+        base::unique_fd bufferFenceDup(dup(bufferFence.get()));
+        if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) {
+            ATRACE_NAME("Waiting before draw");
+            sync_wait(bufferFence.get(), -1);
+        }
     }
 
     if (buffer == nullptr) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 4cd0b3d..32dbad1 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -178,7 +178,6 @@
     EGLSurface mDummySurface;
     EGLContext mProtectedEGLContext;
     EGLSurface mProtectedDummySurface;
-    GLuint mProtectedTexName;
     GLint mMaxViewportDims[2];
     GLint mMaxTextureSize;
     GLuint mVpWidth;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 6fd4b80..d8e4059 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -77,6 +77,7 @@
     outDescriptorInfo->layerCount = layerCount;
     outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
     outDescriptorInfo->usage = usage;
+    outDescriptorInfo->reservedSize = 0;
 }
 
 } // anonymous namespace
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index cd2a448..bf487c4 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -67,20 +67,19 @@
 // ----------------------------------------------------------------------------
 
 Region::Region() {
-    mStorage.push_back(Rect(0, 0));
+    mStorage.add(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.push_back(rhs);
+    mStorage.add(rhs);
 }
 
 Region::~Region()
@@ -101,8 +100,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, FatVector<Rect>& dst,
-                                           int spanDirection) {
+static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
+        Vector<Rect>& dst, int spanDirection) {
     dst.clear();
 
     const Rect* current = end - 1;
@@ -110,7 +109,7 @@
 
     // add first span immediately
     do {
-        dst.push_back(*current);
+        dst.add(*current);
         current--;
     } while (current->top == lastTop && current >= begin);
 
@@ -148,12 +147,12 @@
                 if (prev.right <= left) break;
 
                 if (prev.right > left && prev.right < right) {
-                    dst.push_back(Rect(prev.right, top, right, bottom));
+                    dst.add(Rect(prev.right, top, right, bottom));
                     right = prev.right;
                 }
 
                 if (prev.left > left && prev.left < right) {
-                    dst.push_back(Rect(prev.left, top, right, bottom));
+                    dst.add(Rect(prev.left, top, right, bottom));
                     right = prev.left;
                 }
 
@@ -167,12 +166,12 @@
                 if (prev.left >= right) break;
 
                 if (prev.left > left && prev.left < right) {
-                    dst.push_back(Rect(left, top, prev.left, bottom));
+                    dst.add(Rect(left, top, prev.left, bottom));
                     left = prev.left;
                 }
 
                 if (prev.right > left && prev.right < right) {
-                    dst.push_back(Rect(left, top, prev.right, bottom));
+                    dst.add(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
@@ -184,7 +183,7 @@
         }
 
         if (left < right) {
-            dst.push_back(Rect(left, top, right, bottom));
+            dst.add(Rect(left, top, right, bottom));
         }
 
         current--;
@@ -202,14 +201,13 @@
     if (r.isEmpty()) return r;
     if (r.isRect()) return r;
 
-    FatVector<Rect> reversed;
+    Vector<Rect> reversed;
     reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
 
     Region outputRegion;
-    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
+    reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
+            outputRegion.mStorage, direction_LTR);
+    outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
 
 #if defined(VALIDATE_REGIONS)
     validate(outputRegion, "T-Junction free region");
@@ -224,8 +222,7 @@
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
-    mStorage.clear();
-    mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
+    mStorage = rhs.mStorage;
     return *this;
 }
 
@@ -234,7 +231,7 @@
     if (mStorage.size() >= 2) {
         const Rect bounds(getBounds());
         mStorage.clear();
-        mStorage.push_back(bounds);
+        mStorage.add(bounds);
     }
     return *this;
 }
@@ -258,25 +255,25 @@
 void Region::clear()
 {
     mStorage.clear();
-    mStorage.push_back(Rect(0, 0));
+    mStorage.add(Rect(0,0));
 }
 
 void Region::set(const Rect& r)
 {
     mStorage.clear();
-    mStorage.push_back(r);
+    mStorage.add(r);
 }
 
 void Region::set(int32_t w, int32_t h)
 {
     mStorage.clear();
-    mStorage.push_back(Rect(w, h));
+    mStorage.add(Rect(w, h));
 }
 
 void Region::set(uint32_t w, uint32_t h)
 {
     mStorage.clear();
-    mStorage.push_back(Rect(w, h));
+    mStorage.add(Rect(w, h));
 }
 
 bool Region::isTriviallyEqual(const Region& region) const {
@@ -302,7 +299,8 @@
 void Region::addRectUnchecked(int l, int t, int r, int b)
 {
     Rect rect(l,t,r,b);
-    mStorage.insert(mStorage.end() - 1, rect);
+    size_t where = mStorage.size() - 1;
+    mStorage.insertAt(rect, where, 1);
 }
 
 // ----------------------------------------------------------------------------
@@ -352,7 +350,7 @@
 
 Region& Region::scaleSelf(float sx, float sy) {
     size_t count = mStorage.size();
-    Rect* rects = mStorage.data();
+    Rect* rects = mStorage.editArray();
     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);
@@ -457,10 +455,10 @@
 class Region::rasterizer : public region_operator<Rect>::region_rasterizer
 {
     Rect bounds;
-    FatVector<Rect>& storage;
+    Vector<Rect>& storage;
     Rect* head;
     Rect* tail;
-    FatVector<Rect> span;
+    Vector<Rect> span;
     Rect* cur;
 public:
     explicit rasterizer(Region& reg)
@@ -487,8 +485,8 @@
         flushSpan();
     }
     if (storage.size()) {
-        bounds.top = storage.front().top;
-        bounds.bottom = storage.back().bottom;
+        bounds.top = storage.itemAt(0).top;
+        bounds.bottom = storage.top().bottom;
         if (storage.size() == 1) {
             storage.clear();
         }
@@ -496,7 +494,7 @@
         bounds.left  = 0;
         bounds.right = 0;
     }
-    storage.push_back(bounds);
+    storage.add(bounds);
 }
 
 void Region::rasterizer::operator()(const Rect& rect)
@@ -511,15 +509,15 @@
             return;
         }
     }
-    span.push_back(rect);
-    cur = span.data() + (span.size() - 1);
+    span.add(rect);
+    cur = span.editArray() + (span.size() - 1);
 }
 
 void Region::rasterizer::flushSpan()
 {
     bool merge = false;
     if (tail-head == ssize_t(span.size())) {
-        Rect const* p = span.data();
+        Rect const* p = span.editArray();
         Rect const* q = head;
         if (p->top == q->bottom) {
             merge = true;
@@ -534,17 +532,17 @@
         }
     }
     if (merge) {
-        const int bottom = span.front().bottom;
+        const int bottom = span[0].bottom;
         Rect* r = head;
         while (r != tail) {
             r->bottom = bottom;
             r++;
         }
     } else {
-        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();
+        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();
         head = tail - span.size();
     }
     span.clear();
@@ -552,7 +550,7 @@
 
 bool Region::validate(const Region& reg, const char* name, bool silent)
 {
-    if (reg.mStorage.empty()) {
+    if (reg.mStorage.isEmpty()) {
         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;
@@ -691,8 +689,9 @@
     }
     sk_dst.op(sk_lhs, sk_rhs, sk_op);
 
-    if (sk_dst.empty() && dst.empty()) return;
-
+    if (sk_dst.isEmpty() && dst.isEmpty())
+        return;
+    
     bool same = true;
     Region::const_iterator head = dst.begin();
     Region::const_iterator const tail = dst.end();
@@ -787,7 +786,7 @@
         validate(reg, "translate (before)");
 #endif
         size_t count = reg.mStorage.size();
-        Rect* rects = reg.mStorage.data();
+        Rect* rects = reg.mStorage.editArray();
         while (count) {
             rects->offsetBy(dx, dy);
             rects++;
@@ -867,25 +866,24 @@
         ALOGE("Region::unflatten() failed, invalid region");
         return BAD_VALUE;
     }
-    mStorage.clear();
-    mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
+    mStorage = result.mStorage;
     return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
 
 Region::const_iterator Region::begin() const {
-    return mStorage.data();
+    return mStorage.array();
 }
 
 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.empty()) return mStorage.data();
+    if (mStorage.isEmpty()) return mStorage.array();
 
     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
-    return mStorage.data() + numRects;
+    return mStorage.array() + numRects;
 }
 
 Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
deleted file mode 100644
index 25fe3a0..0000000
--- a/libs/ui/include/ui/FatVector.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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 6bb7b8d..2db3b10 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.
-    FatVector<Rect> mStorage;
+    Vector<Rect> mStorage;
 };
 
 
@@ -235,3 +235,4 @@
 }; // namespace android
 
 #endif // ANDROID_UI_REGION_H
+
diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h
deleted file mode 120000
index bf30166..0000000
--- a/libs/ui/include_vndk/ui/FatVector.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/ui/FatVector.h
\ No newline at end of file
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 67d69b4..a58e87c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -158,13 +158,16 @@
             // 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:
-            ALOGV("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
+            ALOGE("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
             break;
     }
-    attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
-    attrs.push_back(EGL_FALSE);
 
     return true;
 }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index d30c4f1..1f283b1 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1445,7 +1445,6 @@
 
     ASSERT_EQ(keyArgs.action, verifiedKey.action);
     ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
-    ASSERT_EQ(keyArgs.eventTime, verifiedKey.eventTimeNanos);
     ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
     ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
     ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
@@ -1453,6 +1452,43 @@
     ASSERT_EQ(0, verifiedKey.repeatCount);
 }
 
+TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    InputEvent* event = window->consume();
+    ASSERT_NE(event, nullptr);
+
+    std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
+    ASSERT_NE(verified, nullptr);
+    ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
+
+    EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos);
+    EXPECT_EQ(motionArgs.deviceId, verified->deviceId);
+    EXPECT_EQ(motionArgs.source, verified->source);
+    EXPECT_EQ(motionArgs.displayId, verified->displayId);
+
+    const VerifiedMotionEvent& verifiedMotion = static_cast<const VerifiedMotionEvent&>(*verified);
+
+    EXPECT_EQ(motionArgs.pointerCoords[0].getX(), verifiedMotion.rawX);
+    EXPECT_EQ(motionArgs.pointerCoords[0].getY(), verifiedMotion.rawY);
+    EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked);
+    EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos);
+    EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags);
+    EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState);
+    EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
+}
+
 class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
 protected:
     static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 3e0f136..b0d3e3b 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -9,7 +9,7 @@
     ],
 
     aidl: {
-       local_include_dirs: ["."],
+       local_include_dirs: ["include"],
        include_dirs: [
            "frameworks/base/core/java/android/os",
        ],
@@ -28,6 +28,11 @@
         "-Wunused",
         "-Wunreachable-code",
     ],
+
+    local_include_dirs: ["include"],
+    export_include_dirs: [
+         "include",
+    ],
 }
 
 cc_test {
diff --git a/include/android/CoolingDevice.h b/services/powermanager/include/android/CoolingDevice.h
similarity index 100%
rename from include/android/CoolingDevice.h
rename to services/powermanager/include/android/CoolingDevice.h
diff --git a/include/android/Temperature.h b/services/powermanager/include/android/Temperature.h
similarity index 100%
rename from include/android/Temperature.h
rename to services/powermanager/include/android/Temperature.h
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d7ec868..e4d754c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -485,6 +485,10 @@
         }
     }
 
+    if (recomputeVisibleRegions == true) {
+        maybeDirtyInput();
+    }
+
     return true;
 }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f5a99ca..4e5c593 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -346,8 +346,6 @@
     mPreviousBufferId = getCurrentBufferId();
     mBufferInfo.mBuffer =
             mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence);
-    auto* layerCompositionState = editCompositionState();
-    layerCompositionState->buffer = mBufferInfo.mBuffer;
 
     if (mBufferInfo.mBuffer == nullptr) {
         // this can only happen if the very first buffer was rejected.
@@ -441,7 +439,7 @@
         mQueueItemCondition.broadcast();
     }
 
-    mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+    mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(),
                                              item.mGraphicBuffer->getHeight(), item.mFrameNumber);
 
     mFlinger->signalLayerUpdate();
@@ -564,8 +562,6 @@
     mBufferInfo.mApi = mConsumer->getCurrentApi();
     mBufferInfo.mPixelFormat = mFormat;
     mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
-    float latchedFrameRate;
-    mConsumer->getFrameRate(&latchedFrameRate);
 }
 
 sp<Layer> BufferQueueLayer::createClone() {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index de5429b..3ed6889 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -616,7 +616,6 @@
     mPreviousBufferId = getCurrentBufferId();
     mBufferInfo.mBuffer = s.buffer;
     mBufferInfo.mFence = s.acquireFence;
-    editCompositionState()->buffer = mBufferInfo.mBuffer;
 
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index 9aaef65..f24f314 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -104,9 +104,8 @@
     return static_cast<uint16_t>(value >> 40);
 }
 
-DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
-    return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(displayNameHash) << 8) |
-            port};
+DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash) {
+    return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(modelHash) << 8) | port};
 }
 
 bool isEdid(const DisplayIdentificationData& data) {
@@ -209,23 +208,30 @@
         view.remove_prefix(kDescriptorLength);
     }
 
-    if (displayName.empty()) {
+    std::string_view modelString = displayName;
+
+    if (modelString.empty()) {
         ALOGW("Invalid EDID: falling back to serial number due to missing display name.");
-        displayName = serialNumber;
+        modelString = serialNumber;
     }
-    if (displayName.empty()) {
+    if (modelString.empty()) {
         ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number.");
-        displayName = asciiText;
+        modelString = asciiText;
     }
-    if (displayName.empty()) {
+    if (modelString.empty()) {
         ALOGE("Invalid EDID: display name and fallback descriptors are missing.");
         return {};
     }
 
+    // Hash model string instead of using product code or (integer) serial number, since the latter
+    // have been observed to change on some displays with multiple inputs.
+    const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString));
+
     return Edid{.manufacturerId = manufacturerId,
-                .pnpId = *pnpId,
-                .displayName = displayName,
                 .productId = productId,
+                .pnpId = *pnpId,
+                .modelHash = modelHash,
+                .displayName = displayName,
                 .manufactureWeek = manufactureWeek,
                 .manufactureOrModelYear = manufactureOrModelYear};
 }
@@ -253,10 +259,8 @@
         return {};
     }
 
-    // Hash display name instead of using product code or serial number, since the latter have been
-    // observed to change on some displays with multiple inputs.
-    const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
-    return DisplayIdentificationInfo{.id = DisplayId::fromEdid(port, edid->manufacturerId, hash),
+    const auto displayId = DisplayId::fromEdid(port, edid->manufacturerId, edid->modelHash);
+    return DisplayIdentificationInfo{.id = displayId,
                                      .name = std::string(edid->displayName),
                                      .deviceProductInfo = buildDeviceProductInfo(*edid)};
 }
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 0a18ba1..d91b957 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -34,7 +34,7 @@
 
     uint16_t manufacturerId() const;
 
-    static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash);
+    static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash);
 };
 
 inline bool operator==(DisplayId lhs, DisplayId rhs) {
@@ -61,6 +61,7 @@
     uint16_t manufacturerId;
     uint16_t productId;
     PnpId pnpId;
+    uint32_t modelHash;
     std::string_view displayName;
     uint8_t manufactureOrModelYear;
     uint8_t manufactureWeek;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 36544b6..aeffb0e 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -57,9 +57,12 @@
  */
 
 FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,
-                                       const sp<IGraphicBufferConsumer>& consumer)
+                                       const sp<IGraphicBufferConsumer>& consumer,
+                                       uint32_t maxWidth, uint32_t maxHeight)
       : ConsumerBase(consumer),
         mDisplayId(displayId),
+        mMaxWidth(maxWidth),
+        mMaxHeight(maxHeight),
         mCurrentBufferSlot(-1),
         mCurrentBuffer(),
         mCurrentFence(Fence::NO_FENCE),
@@ -75,14 +78,16 @@
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
     const auto& activeConfig = mHwc.getActiveConfig(displayId);
-    mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
-            activeConfig->getHeight());
+    ui::Size limitedSize =
+            limitFramebufferSize(activeConfig->getWidth(), activeConfig->getHeight());
+    mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
     mConsumer->setMaxAcquiredBufferCount(
             SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
-void FramebufferSurface::resizeBuffers(const uint32_t width, const uint32_t height) {
-    mConsumer->setDefaultBufferSize(width, height);
+void FramebufferSurface::resizeBuffers(uint32_t width, uint32_t height) {
+    ui::Size limitedSize = limitFramebufferSize(width, height);
+    mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
 }
 
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
@@ -177,6 +182,29 @@
     }
 }
 
+ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) {
+    // TODO(b/149495759): Use the ui::Size constructor once it no longer is broken.
+    ui::Size framebufferSize;
+    framebufferSize.width = width;
+    framebufferSize.height = height;
+    bool wasLimited = true;
+    if (width > mMaxWidth && mMaxWidth != 0) {
+        float aspectRatio = float(width) / float(height);
+        framebufferSize.height = mMaxWidth / aspectRatio;
+        framebufferSize.width = mMaxWidth;
+        wasLimited = true;
+    }
+    if (height > mMaxHeight && mMaxHeight != 0) {
+        float aspectRatio = float(width) / float(height);
+        framebufferSize.height = mMaxHeight;
+        framebufferSize.width = mMaxHeight * aspectRatio;
+        wasLimited = true;
+    }
+    ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]",
+             framebufferSize.width, framebufferSize.height, width, height);
+    return framebufferSize;
+}
+
 void FramebufferSurface::dumpAsString(String8& result) const {
     Mutex::Autolock lock(mMutex);
     result.appendFormat("  FramebufferSurface: dataspace: %s(%d)\n",
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 7f451a5..a1859f3 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -23,6 +23,7 @@
 #include <compositionengine/DisplaySurface.h>
 #include <compositionengine/impl/HwcBufferCache.h>
 #include <gui/ConsumerBase.h>
+#include <ui/Size.h>
 
 #include "DisplayIdentification.h"
 
@@ -39,7 +40,8 @@
 class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
 public:
     FramebufferSurface(HWComposer& hwc, DisplayId displayId,
-                       const sp<IGraphicBufferConsumer>& consumer);
+                       const sp<IGraphicBufferConsumer>& consumer, uint32_t maxWidth,
+                       uint32_t maxHeight);
 
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
@@ -47,7 +49,7 @@
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
 
-    virtual void resizeBuffers(const uint32_t width, const uint32_t height);
+    virtual void resizeBuffers(uint32_t width, uint32_t height);
 
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
@@ -58,6 +60,9 @@
 
     virtual void dumpLocked(String8& result, const char* prefix) const;
 
+    // Limits the width and height by the maximum width specified in the constructor.
+    ui::Size limitFramebufferSize(uint32_t width, uint32_t height);
+
     // nextBuffer waits for and then latches the next buffer from the
     // BufferQueue and releases the previously latched buffer to the
     // BufferQueue.  The new buffer is returned in the 'buffer' argument.
@@ -66,6 +71,14 @@
 
     const DisplayId mDisplayId;
 
+    // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of
+    // the device.
+    const uint32_t mMaxWidth;
+
+    // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of
+    // the device.
+    const uint32_t mMaxHeight;
+
     // mCurrentBufferIndex is the slot index of the current buffer or
     // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
     // or the buffer is not associated with a slot.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b952eb6..d8229c6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -994,6 +994,9 @@
     commitTransaction(c);
     mPendingStatesSnapshot = mPendingStates;
     mCurrentState.callbackHandles = {};
+
+    maybeDirtyInput();
+
     return flags;
 }
 
@@ -2537,6 +2540,32 @@
     }
 }
 
+bool Layer::maybeDirtyInput() {
+    // No sense redirtying input.
+    if (mFlinger->inputDirty()) return true;
+
+    if (hasInput()) {
+        mFlinger->dirtyInput();
+        return true;
+    }
+
+    // If a child or relative dirties the input, no sense continuing to traverse
+    // so we return early and halt the recursion. We traverse ourselves instead
+    // of using traverse() so we can implement this early halt.
+    for (const sp<Layer>& child : mDrawingChildren) {
+        if (child->maybeDirtyInput()) {
+            return true;
+        }
+    }
+    for (const wp<Layer>& weakRelative : mDrawingState.zOrderRelatives) {
+        sp<Layer> relative = weakRelative.promote();
+        if (relative && relative->maybeDirtyInput()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 72f6de3..be80f78 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1002,6 +1002,10 @@
     // Window types from WindowManager.LayoutParams
     const int mWindowType;
 
+    // Called when mDrawingState has changed. If we or one of our children/relatives hasInput()
+    // then we will dirty the setInputWindows cache.
+    bool maybeDirtyInput();
+
 private:
     /**
      * Returns an unsorted vector of all layers that are part of this tree.
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index d3364a0..e6c8654 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -120,7 +120,7 @@
     // We latch the transparent region here, instead of above where we latch
     // the rest of the geometry because it is only content but not necessarily
     // resize dependent.
-    if (!mFront.activeTransparentRegion_legacy.isTriviallyEqual(
+    if (!mFront.activeTransparentRegion_legacy.hasSameRects(
                 mFront.requestedTransparentRegion_legacy)) {
         mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy;
 
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 40a63d7..5009e10 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -162,10 +162,6 @@
     return mProducer->setAutoPrerotation(autoPrerotation);
 }
 
-status_t MonitoredProducer::setFrameRate(float frameRate) {
-    return mProducer->setFrameRate(frameRate);
-}
-
 IBinder* MonitoredProducer::onAsBinder() {
     return this;
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 4bda831..788919b 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -71,7 +71,6 @@
     virtual status_t getUniqueId(uint64_t* outId) const override;
     virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
     virtual status_t setAutoPrerotation(bool autoPrerotation) override;
-    virtual status_t setFrameRate(float frameRate) override;
 
     // The Layer which created this producer, and on which queued Buffer's will be displayed.
     sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 682679c..c675971 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -168,9 +168,9 @@
 }
 
 void RefreshRateOverlay::primeCache() {
-    auto allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
+    auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
     if (allRefreshRates.size() == 1) {
-        auto fps = allRefreshRates.begin()->second.fps;
+        auto fps = allRefreshRates.begin()->second->fps;
         half4 color = {LOW_FPS_COLOR, ALPHA};
         mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
         return;
@@ -178,8 +178,8 @@
 
     std::vector<uint32_t> supportedFps;
     supportedFps.reserve(allRefreshRates.size());
-    for (auto [ignored, refreshRate] : allRefreshRates) {
-        supportedFps.push_back(refreshRate.fps);
+    for (auto& [ignored, refreshRate] : allRefreshRates) {
+        supportedFps.push_back(refreshRate->fps);
     }
 
     std::sort(supportedFps.begin(), supportedFps.end());
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 0031d70..68cd84f 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -201,9 +201,10 @@
 
 void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) {
-    wp<Layer> stopLayer = stopLayerHandle != nullptr
-            ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner
-            : nullptr;
+    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);
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 101060c..8b08592 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -212,7 +212,5 @@
     for (const auto& [layer, info] : activeLayers()) {
         info->clearHistory();
     }
-
-    mActiveLayersEnd = 0;
 }
 } // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 63d9c4b..c04447d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -71,10 +71,10 @@
     std::unordered_map<float, Offsets> offsets;
 
     for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
-        if (refreshRate.fps > 65.0f) {
-            offsets.emplace(refreshRate.fps, getHighFpsOffsets(refreshRate.vsyncPeriod));
+        if (refreshRate->fps > 65.0f) {
+            offsets.emplace(refreshRate->fps, getHighFpsOffsets(refreshRate->vsyncPeriod));
         } else {
-            offsets.emplace(refreshRate.fps, getDefaultOffsets(refreshRate.vsyncPeriod));
+            offsets.emplace(refreshRate->fps, getDefaultOffsets(refreshRate->vsyncPeriod));
         }
     }
     return offsets;
@@ -238,7 +238,7 @@
     refreshRates.reserve(allRefreshRates.size());
 
     for (const auto& [ignored, refreshRate] : allRefreshRates) {
-        refreshRates.emplace_back(refreshRate.fps);
+        refreshRates.emplace_back(refreshRate->fps);
     }
 
     return refreshRates;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 15b158d..02d0b53 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -23,6 +23,9 @@
 #include <chrono>
 #include <cmath>
 
+#undef LOG_TAG
+#define LOG_TAG "RefreshRateConfigs"
+
 namespace android::scheduler {
 
 using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
@@ -95,22 +98,19 @@
 }
 
 const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
-        const std::vector<LayerRequirement>& layers, bool touchActive) const {
+        const std::vector<LayerRequirement>& layers, bool touchActive,
+        bool* touchConsidered) const {
     ATRACE_CALL();
     ALOGV("getRefreshRateForContent %zu layers", layers.size());
 
+    *touchConsidered = false;
     std::lock_guard lock(mLock);
 
-    // For now if the touch is active return the peak refresh rate
-    // This should be optimized to consider other layers as well.
-    if (touchActive) {
-        return *mAvailableRefreshRates.back();
-    }
-
     // If there are not layers, there is not content detection, so return the current
     // refresh rate.
     if (layers.empty()) {
-        return getCurrentRefreshRateByPolicyLocked();
+        *touchConsidered = touchActive;
+        return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
     }
 
     int noVoteLayers = 0;
@@ -118,17 +118,30 @@
     int maxVoteLayers = 0;
     int explicitDefaultVoteLayers = 0;
     int explicitExactOrMultipleVoteLayers = 0;
+    float maxExplicitWeight = 0;
     for (const auto& layer : layers) {
-        if (layer.vote == LayerVoteType::NoVote)
+        if (layer.vote == LayerVoteType::NoVote) {
             noVoteLayers++;
-        else if (layer.vote == LayerVoteType::Min)
+        } else if (layer.vote == LayerVoteType::Min) {
             minVoteLayers++;
-        else if (layer.vote == LayerVoteType::Max)
+        } else if (layer.vote == LayerVoteType::Max) {
             maxVoteLayers++;
-        else if (layer.vote == LayerVoteType::ExplicitDefault)
+        } else if (layer.vote == LayerVoteType::ExplicitDefault) {
             explicitDefaultVoteLayers++;
-        else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple)
+            maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+        } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
             explicitExactOrMultipleVoteLayers++;
+            maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+        }
+    }
+
+    // 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) {
+        *touchConsidered = true;
+        return *mAvailableRefreshRates.back();
     }
 
     // Only if all layers want Min we should return Min
@@ -168,16 +181,17 @@
             const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
             if (layer.vote == LayerVoteType::ExplicitDefault) {
                 const auto layerScore = [&]() {
-                    const auto [displayFramesQuot, displayFramesRem] =
-                            getDisplayFrames(layerPeriod, displayPeriod);
-                    if (displayFramesQuot == 0) {
-                        // Layer desired refresh rate is higher the display rate.
-                        return static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod);
+                    // Find the actual rate the layer will render, assuming
+                    // that layerPeriod is the minimal time to render a frame
+                    auto actualLayerPeriod = displayPeriod;
+                    int multiplier = 1;
+                    while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
+                        multiplier++;
+                        actualLayerPeriod = displayPeriod * multiplier;
                     }
-
-                    return 1.0f -
-                            (static_cast<float>(displayFramesRem) /
-                             static_cast<float>(layerPeriod));
+                    return std::min(1.0f,
+                                    static_cast<float>(layerPeriod) /
+                                            static_cast<float>(actualLayerPeriod));
                 }();
 
                 ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f",
@@ -240,6 +254,7 @@
 
 template <typename Iter>
 const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
+    constexpr auto EPSILON = 0.001f;
     const RefreshRate* bestRefreshRate = begin->first;
     float max = begin->second;
     for (auto i = begin; i != end; ++i) {
@@ -248,7 +263,7 @@
 
         ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
 
-        if (score > max) {
+        if (score > max * (1 + EPSILON)) {
             max = score;
             bestRefreshRate = refreshRate;
         }
@@ -286,12 +301,12 @@
                   mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
         return *mCurrentRefreshRate;
     }
-    return mRefreshRates.at(mDefaultConfig);
+    return *mRefreshRates.at(mDefaultConfig);
 }
 
 void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
     std::lock_guard lock(mLock);
-    mCurrentRefreshRate = &mRefreshRates.at(configId);
+    mCurrentRefreshRate = mRefreshRates.at(configId).get();
 }
 
 RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
@@ -326,7 +341,7 @@
     if (mRefreshRates.count(defaultConfigId) == 0) {
         return BAD_VALUE;
     }
-    const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
+    const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId);
     if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
         return BAD_VALUE;
     }
@@ -361,10 +376,10 @@
     outRefreshRates->clear();
     outRefreshRates->reserve(mRefreshRates.size());
     for (const auto& [type, refreshRate] : mRefreshRates) {
-        if (shouldAddRefreshRate(refreshRate)) {
+        if (shouldAddRefreshRate(*refreshRate)) {
             ALOGV("getSortedRefreshRateList: config %d added to list policy",
-                  refreshRate.configId.value());
-            outRefreshRates->push_back(&refreshRate);
+                  refreshRate->configId.value());
+            outRefreshRates->push_back(refreshRate.get());
         }
     }
 
@@ -376,7 +391,7 @@
 
 void RefreshRateConfigs::constructAvailableRefreshRates() {
     // Filter configs based on current policy and sort based on vsync period
-    HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
+    HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig)->configGroup;
     ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
           mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
     getSortedRefreshRateList(
@@ -403,16 +418,15 @@
     LOG_ALWAYS_FATAL_IF(configs.empty());
     LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
 
-    auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
-        const float fps = 1e9f / config.vsyncPeriod;
-        return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
-                           base::StringPrintf("%2.ffps", fps), fps);
-    };
-
     for (const auto& config : configs) {
-        mRefreshRates.emplace(config.configId, buildRefreshRate(config));
+        const float fps = 1e9f / config.vsyncPeriod;
+        mRefreshRates.emplace(config.configId,
+                              std::make_unique<RefreshRate>(config.configId, config.vsyncPeriod,
+                                                            config.configGroup,
+                                                            base::StringPrintf("%2.ffps", fps),
+                                                            fps));
         if (config.configId == currentHwcConfig) {
-            mCurrentRefreshRate = &mRefreshRates.at(config.configId);
+            mCurrentRefreshRate = mRefreshRates.at(config.configId).get();
         }
     }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index c8aec86..87d4389 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -59,6 +59,8 @@
                 configGroup(configGroup),
                 name(std::move(name)),
                 fps(fps) {}
+
+        RefreshRate(const RefreshRate&) = delete;
         // This config ID corresponds to the position of the config in the vector that is stored
         // on the device.
         const HwcConfigIndexType configId;
@@ -85,7 +87,8 @@
         bool operator==(const RefreshRate& other) const { return !(*this != other); }
     };
 
-    using AllRefreshRatesMapType = std::unordered_map<HwcConfigIndexType, const RefreshRate>;
+    using AllRefreshRatesMapType =
+            std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
 
     // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is
     // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true
@@ -134,9 +137,11 @@
 
     // 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.
+    // 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) const EXCLUDES(mLock);
+                                                  bool touchActive, bool* touchConsidered) const
+            EXCLUDES(mLock);
 
     // Returns all the refresh rates supported by the device. This won't change at runtime.
     const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock);
@@ -163,7 +168,7 @@
     // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at
     // runtime.
     const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const {
-        return mRefreshRates.at(configId);
+        return *mRefreshRates.at(configId);
     };
 
     // Stores the current configId the device operates at
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5444239..920f0ec 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -463,7 +463,7 @@
             return;
         }
         mFeatures.configId = newConfigId;
-        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
         mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
     }
 }
@@ -483,7 +483,7 @@
     // that is currently on top. b/142507166 will give us this capability.
     std::lock_guard<std::mutex> lock(mFeatureStateLock);
     if (mLayerHistory) {
-        mLayerHistory->clear();
+        // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2
 
         mTouchTimer->reset();
 
@@ -515,7 +515,7 @@
 
     // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
     // magic number
-    const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+    const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
     constexpr float FPS_THRESHOLD_FOR_KERNEL_TIMER = 65.0f;
     if (state == TimerState::Reset && refreshRate.fps > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
         // If we're not in performance mode then the kernel timer shouldn't do
@@ -620,10 +620,21 @@
         return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId;
     }
 
-    return mRefreshRateConfigs
-            .getRefreshRateForContentV2(mFeatures.contentRequirements,
-                                        mTouchTimer && mFeatures.touch == TouchState::Active)
-            .configId;
+    bool touchConsidered;
+    const auto& ret =
+            mRefreshRateConfigs
+                    .getRefreshRateForContentV2(mFeatures.contentRequirements,
+                                                mTouchTimer &&
+                                                        mFeatures.touch == TouchState::Active,
+                                                &touchConsidered)
+                    .configId;
+    if (touchConsidered) {
+        // Clear layer history if refresh rate was selected based on touch to allow
+        // the hueristic to pick up with the new rate.
+        mLayerHistory->clear();
+    }
+
+    return ret;
 }
 
 std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 949ba4c..8987dcd 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -19,8 +19,10 @@
 #define LOG_TAG "VSyncReactor"
 //#define LOG_NDEBUG 0
 #include "VSyncReactor.h"
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <utils/Trace.h>
+#include "../TracedOrdinal.h"
 #include "TimeKeeper.h"
 #include "VSyncDispatch.h"
 #include "VSyncTracker.h"
@@ -32,12 +34,35 @@
     return systemTime(SYSTEM_TIME_MONOTONIC);
 }
 
+class PredictedVsyncTracer {
+public:
+    PredictedVsyncTracer(VSyncDispatch& dispatch)
+          : mRegistration(dispatch,
+                          std::bind(&PredictedVsyncTracer::callback, this, std::placeholders::_1,
+                                    std::placeholders::_2),
+                          "PredictedVsyncTracer") {
+        mRegistration.schedule(0, 0);
+    }
+
+private:
+    TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0};
+    VSyncCallbackRegistration mRegistration;
+
+    void callback(nsecs_t /*vsyncTime*/, nsecs_t /*targetWakeupTim*/) {
+        mParity = !mParity;
+        mRegistration.schedule(0, 0);
+    }
+};
+
 VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
                            std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit)
       : mClock(std::move(clock)),
         mTracker(std::move(tracker)),
         mDispatch(std::move(dispatch)),
-        mPendingLimit(pendingFenceLimit) {}
+        mPendingLimit(pendingFenceLimit),
+        mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false)
+                                      ? std::make_unique<PredictedVsyncTracer>(*mDispatch)
+                                      : nullptr) {}
 
 VSyncReactor::~VSyncReactor() = default;
 
@@ -287,7 +312,7 @@
     auto it = mCallbacks.find(callback);
     if (it == mCallbacks.end()) {
         // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f.
-        static auto constexpr maxListeners = 3;
+        static auto constexpr maxListeners = 4;
         if (mCallbacks.size() >= maxListeners) {
             ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name,
                   maxListeners, mCallbacks.size());
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index aa8a38d..7d8a8e3 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -30,6 +30,7 @@
 class VSyncDispatch;
 class VSyncTracker;
 class CallbackRepeater;
+class PredictedVsyncTracer;
 
 // TODO (b/145217110): consider renaming.
 class VSyncReactor : public android::DispSync {
@@ -86,6 +87,8 @@
 
     std::unordered_map<DispSync::Callback*, std::unique_ptr<CallbackRepeater>> mCallbacks
             GUARDED_BY(mMutex);
+
+    const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
 };
 
 class SystemClock : public Clock {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 67b02c8..cfaabfc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -217,6 +217,8 @@
 bool SurfaceFlinger::hasSyncFramework;
 bool SurfaceFlinger::useVrFlinger;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+uint32_t SurfaceFlinger::maxGraphicsWidth;
+uint32_t SurfaceFlinger::maxGraphicsHeight;
 bool SurfaceFlinger::hasWideColorDisplay;
 ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0;
 bool SurfaceFlinger::useColorManagement;
@@ -283,6 +285,9 @@
 
     maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
 
+    maxGraphicsWidth = std::max(max_graphics_width(0), 0);
+    maxGraphicsHeight = std::max(max_graphics_height(0), 0);
+
     hasWideColorDisplay = has_wide_color_display(false);
 
     useColorManagement = use_color_management(false);
@@ -359,15 +364,12 @@
 
     property_get("ro.surface_flinger.supports_background_blur", value, "0");
     bool supportsBlurs = atoi(value);
-    property_get("debug.sf.disable_blurs", value, "0");
-    bool disableBlurs = atoi(value);
-    mEnableBlurs = supportsBlurs && !disableBlurs;
-    ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs,
-             disableBlurs);
+    mSupportsBlur = supportsBlurs;
+    ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported.");
     property_get("ro.sf.blurs_are_expensive", value, "0");
     mBlursAreExpensive = atoi(value);
 
-    const size_t defaultListSize = MAX_LAYERS;
+    const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS;
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
 
@@ -404,6 +406,7 @@
 void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
 {
     // the window manager died on us. prepare its eulogy.
+    mBootFinished = false;
 
     // restore initial conditions (default device unblank, etc)
     initializeDisplays();
@@ -520,6 +523,11 @@
 
 void SurfaceFlinger::bootFinished()
 {
+    if (mBootFinished == true) {
+        ALOGE("Extra call to bootFinished");
+        return;
+    }
+    mBootFinished = true;
     if (mStartPropertySetThread->join() != NO_ERROR) {
         ALOGE("Join StartPropertySetThread failed!");
     }
@@ -614,7 +622,7 @@
                 .setUseColorManagerment(useColorManagement)
                 .setEnableProtectedContext(enable_protected_contents(false))
                 .setPrecacheToneMapperShaderOnly(false)
-                .setSupportsBackgroundBlur(mEnableBlurs)
+                .setSupportsBackgroundBlur(mSupportsBlur)
                 .setContextPriority(useContextPriority
                         ? renderengine::RenderEngine::ContextPriority::HIGH
                         : renderengine::RenderEngine::ContextPriority::MEDIUM)
@@ -696,6 +704,11 @@
 
     property_get("persist.sys.sf.color_mode", value, "0");
     mForceColorMode = static_cast<ColorMode>(atoi(value));
+
+    property_get("persist.sys.sf.disable_blurs", value, "0");
+    bool disableBlurs = atoi(value);
+    mDisableBlurs = disableBlurs;
+    ALOGI_IF(disableBlurs, "Disabling blur effects, user preference.");
 }
 
 void SurfaceFlinger::startBootAnim() {
@@ -903,18 +916,27 @@
 
 void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
-    auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
+    auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
     ALOGV("setDesiredActiveConfig(%s)", refreshRate.name.c_str());
 
-    // Don't check against the current mode yet. Worst case we set the desired
-    // config twice. However event generation config might have changed so we need to update it
-    // accordingly
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
-    mDesiredActiveConfig = info;
-    mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
+    if (mDesiredActiveConfigChanged) {
+        // If a config change is pending, just cache the latest request in
+        // mDesiredActiveConfig
+        const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+        mDesiredActiveConfig = info;
+        mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
+    } else {
+        // Check is we are already at the desired config
+        const auto display = getDefaultDisplayDeviceLocked();
+        if (!display || display->getActiveConfig() == refreshRate.configId) {
+            return;
+        }
 
-    if (!mDesiredActiveConfigChanged) {
+        // Initiate a config change.
+        mDesiredActiveConfigChanged = true;
+        mDesiredActiveConfig = info;
+
         // This will trigger HWC refresh without resetting the idle timer.
         repaintEverythingForHWC();
         // Start receiving vsync samples now, so that we can detect a period
@@ -927,7 +949,6 @@
         mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
         mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
     }
-    mDesiredActiveConfigChanged = true;
 
     if (mRefreshRateOverlay) {
         mRefreshRateOverlay->changeRefreshRate(refreshRate);
@@ -976,7 +997,7 @@
     mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
     display->setActiveConfig(mUpcomingActiveConfig.configId);
 
-    auto refreshRate =
+    auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
     mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
     mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
@@ -996,7 +1017,7 @@
     mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
     mDesiredActiveConfigChanged = false;
 
-    auto const refreshRate =
+    const auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
     mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod);
     mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
@@ -1029,7 +1050,7 @@
         desiredActiveConfig = mDesiredActiveConfig;
     }
 
-    auto refreshRate =
+    auto& refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig.configId);
     ALOGV("performSetActiveConfig changing active config to %d(%s)", refreshRate.configId.value(),
           refreshRate.name.c_str());
@@ -1066,7 +1087,9 @@
                                                            mUpcomingActiveConfig.configId.value(),
                                                            constraints, &outTimeline);
     if (status != NO_ERROR) {
-        LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status);
+        // setActiveConfigWithConstraints may fail if a hotplug event is just about
+        // to be sent. We just log the error in this case.
+        ALOGW("setActiveConfigWithConstraints failed: %d", status);
         return false;
     }
 
@@ -2362,13 +2385,14 @@
 sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
         const wp<IBinder>& displayToken,
         std::shared_ptr<compositionengine::Display> compositionDisplay,
-        const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
+        const DisplayDeviceState& state,
+        const sp<compositionengine::DisplaySurface>& displaySurface,
         const sp<IGraphicBufferProducer>& producer) {
     auto displayId = compositionDisplay->getDisplayId();
     DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay);
     creationArgs.sequenceId = state.sequenceId;
     creationArgs.isSecure = state.isSecure;
-    creationArgs.displaySurface = dispSurface;
+    creationArgs.displaySurface = displaySurface;
     creationArgs.hasWideColorGamut = false;
     creationArgs.supportedPerFrameMetadata = 0;
 
@@ -2444,6 +2468,140 @@
     return display;
 }
 
+void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
+                                         const DisplayDeviceState& state) {
+    int width = 0;
+    int height = 0;
+    ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
+    if (state.physical) {
+        const auto& activeConfig =
+                getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id);
+        width = activeConfig->getWidth();
+        height = activeConfig->getHeight();
+        pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
+    } else if (state.surface != nullptr) {
+        int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
+        ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
+        status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+        ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
+        int intPixelFormat;
+        status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
+        ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
+        pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
+    } else {
+        // Virtual displays without a surface are dormant:
+        // they have external state (layer stack, projection,
+        // etc.) but no internal state (i.e. a DisplayDevice).
+        return;
+    }
+
+    compositionengine::DisplayCreationArgsBuilder builder;
+    if (const auto& physical = state.physical) {
+        builder.setPhysical({physical->id, physical->type});
+    }
+    builder.setPixels(ui::Size(width, height));
+    builder.setPixelFormat(pixelFormat);
+    builder.setIsSecure(state.isSecure);
+    builder.setLayerStackId(state.layerStack);
+    builder.setPowerAdvisor(&mPowerAdvisor);
+    builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer());
+    builder.setName(state.displayName);
+    const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
+
+    sp<compositionengine::DisplaySurface> displaySurface;
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferProducer> bqProducer;
+    sp<IGraphicBufferConsumer> bqConsumer;
+    getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false);
+
+    std::optional<DisplayId> displayId = compositionDisplay->getId();
+
+    if (state.isVirtual()) {
+        sp<VirtualDisplaySurface> vds =
+                new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer,
+                                          bqConsumer, state.displayName);
+
+        displaySurface = vds;
+        producer = vds;
+    } else {
+        ALOGE_IF(state.surface != nullptr,
+                 "adding a supported display, but rendering "
+                 "surface is provided (%p), ignoring it",
+                 state.surface.get());
+
+        LOG_ALWAYS_FATAL_IF(!displayId);
+        displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer,
+                                                maxGraphicsWidth, maxGraphicsHeight);
+        producer = bqProducer;
+    }
+
+    if (displaySurface != nullptr) {
+        mDisplays.emplace(displayToken,
+                          setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+                                                        displaySurface, producer));
+        if (!state.isVirtual()) {
+            LOG_ALWAYS_FATAL_IF(!displayId);
+            dispatchDisplayHotplugEvent(displayId->value, true);
+        }
+
+        const auto displayDevice = mDisplays[displayToken];
+        if (displayDevice->isPrimary()) {
+            mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() *
+                                                    displayDevice->getHeight());
+        }
+    }
+}
+
+void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
+    if (const auto display = getDisplayDeviceLocked(displayToken)) {
+        // Save display ID before disconnecting.
+        const auto displayId = display->getId();
+        display->disconnect();
+
+        if (!display->isVirtual()) {
+            LOG_ALWAYS_FATAL_IF(!displayId);
+            dispatchDisplayHotplugEvent(displayId->value, false);
+        }
+    }
+
+    mDisplays.erase(displayToken);
+}
+
+void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
+                                           const DisplayDeviceState& currentState,
+                                           const DisplayDeviceState& drawingState) {
+    const sp<IBinder> currentBinder = IInterface::asBinder(currentState.surface);
+    const sp<IBinder> drawingBinder = IInterface::asBinder(drawingState.surface);
+    if (currentBinder != drawingBinder) {
+        // changing the surface is like destroying and recreating the DisplayDevice
+        if (const auto display = getDisplayDeviceLocked(displayToken)) {
+            display->disconnect();
+        }
+        mDisplays.erase(displayToken);
+        processDisplayAdded(displayToken, currentState);
+        return;
+    }
+
+    if (const auto display = getDisplayDeviceLocked(displayToken)) {
+        if (currentState.layerStack != drawingState.layerStack) {
+            display->setLayerStack(currentState.layerStack);
+        }
+        if ((currentState.orientation != drawingState.orientation) ||
+            (currentState.viewport != drawingState.viewport) ||
+            (currentState.frame != drawingState.frame)) {
+            display->setProjection(currentState.orientation, currentState.viewport,
+                                   currentState.frame);
+        }
+        if (currentState.width != drawingState.width ||
+            currentState.height != drawingState.height) {
+            display->setDisplaySize(currentState.width, currentState.height);
+            if (display->isPrimary()) {
+                mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
+            }
+        }
+    }
+}
+
 void SurfaceFlinger::processDisplayChangesLocked() {
     // here we take advantage of Vector's copy-on-write semantics to
     // improve performance by skipping the transaction entirely when
@@ -2452,158 +2610,31 @@
     const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
     if (!curr.isIdenticalTo(draw)) {
         mVisibleRegionsDirty = true;
-        const size_t cc = curr.size();
-        size_t dc = draw.size();
 
         // find the displays that were removed
         // (ie: in drawing state but not in current state)
         // also handle displays that changed
         // (ie: displays that are in both lists)
-        for (size_t i = 0; i < dc;) {
-            const ssize_t j = curr.indexOfKey(draw.keyAt(i));
+        for (size_t i = 0; i < draw.size(); i++) {
+            const wp<IBinder>& displayToken = draw.keyAt(i);
+            const ssize_t j = curr.indexOfKey(displayToken);
             if (j < 0) {
                 // in drawing state but not in current state
-                if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
-                    // Save display ID before disconnecting.
-                    const auto displayId = display->getId();
-                    display->disconnect();
-
-                    if (!display->isVirtual()) {
-                        LOG_ALWAYS_FATAL_IF(!displayId);
-                        dispatchDisplayHotplugEvent(displayId->value, false);
-                    }
-                }
-
-                mDisplays.erase(draw.keyAt(i));
+                processDisplayRemoved(displayToken);
             } else {
                 // this display is in both lists. see if something changed.
-                const DisplayDeviceState& state(curr[j]);
-                const wp<IBinder>& displayToken = curr.keyAt(j);
-                const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
-                const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
-                if (state_binder != draw_binder) {
-                    // changing the surface is like destroying and
-                    // recreating the DisplayDevice, so we just remove it
-                    // from the drawing state, so that it get re-added
-                    // below.
-                    if (const auto display = getDisplayDeviceLocked(displayToken)) {
-                        display->disconnect();
-                    }
-                    mDisplays.erase(displayToken);
-                    mDrawingState.displays.removeItemsAt(i);
-                    dc--;
-                    // at this point we must loop to the next item
-                    continue;
-                }
-
-                if (const auto display = getDisplayDeviceLocked(displayToken)) {
-                    if (state.layerStack != draw[i].layerStack) {
-                        display->setLayerStack(state.layerStack);
-                    }
-                    if ((state.orientation != draw[i].orientation) ||
-                        (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
-                        display->setProjection(state.orientation, state.viewport, state.frame);
-                    }
-                    if (state.width != draw[i].width || state.height != draw[i].height) {
-                        display->setDisplaySize(state.width, state.height);
-                        if (display->isPrimary()) {
-                            mScheduler->onPrimaryDisplayAreaChanged(state.width * state.height);
-                        }
-                    }
-                }
+                const DisplayDeviceState& currentState = curr[j];
+                const DisplayDeviceState& drawingState = draw[i];
+                processDisplayChanged(displayToken, currentState, drawingState);
             }
-            ++i;
         }
 
         // find displays that were added
         // (ie: in current state but not in drawing state)
-        for (size_t i = 0; i < cc; i++) {
-            if (draw.indexOfKey(curr.keyAt(i)) < 0) {
-                const DisplayDeviceState& state(curr[i]);
-
-                int width = 0;
-                int height = 0;
-                ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
-                if (state.physical) {
-                    const auto& activeConfig =
-                            getCompositionEngine().getHwComposer().getActiveConfig(
-                                    state.physical->id);
-                    width = activeConfig->getWidth();
-                    height = activeConfig->getHeight();
-                    pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
-                } else if (state.surface != nullptr) {
-                    int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
-                    ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
-                    status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
-                    ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
-                    int intPixelFormat;
-                    status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
-                    ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
-                    pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
-                } else {
-                    // Virtual displays without a surface are dormant:
-                    // they have external state (layer stack, projection,
-                    // etc.) but no internal state (i.e. a DisplayDevice).
-                    continue;
-                }
-
-                compositionengine::DisplayCreationArgsBuilder builder;
-                if (const auto& physical = state.physical) {
-                    builder.setPhysical({physical->id, physical->type});
-                }
-                builder.setPixels(ui::Size(width, height));
-                builder.setPixelFormat(pixelFormat);
-                builder.setIsSecure(state.isSecure);
-                builder.setLayerStackId(state.layerStack);
-                builder.setPowerAdvisor(&mPowerAdvisor);
-                builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays ||
-                                                 getHwComposer().isUsingVrComposer());
-                builder.setName(state.displayName);
-                auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
-
-                sp<compositionengine::DisplaySurface> dispSurface;
-                sp<IGraphicBufferProducer> producer;
-                sp<IGraphicBufferProducer> bqProducer;
-                sp<IGraphicBufferConsumer> bqConsumer;
-                getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
-
-                std::optional<DisplayId> displayId = compositionDisplay->getId();
-
-                if (state.isVirtual()) {
-                    sp<VirtualDisplaySurface> vds =
-                            new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
-                                                      bqProducer, bqConsumer, state.displayName);
-
-                    dispSurface = vds;
-                    producer = vds;
-                } else {
-                    ALOGE_IF(state.surface != nullptr,
-                             "adding a supported display, but rendering "
-                             "surface is provided (%p), ignoring it",
-                             state.surface.get());
-
-                    LOG_ALWAYS_FATAL_IF(!displayId);
-                    dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
-                    producer = bqProducer;
-                }
-
-                const wp<IBinder>& displayToken = curr.keyAt(i);
-                if (dispSurface != nullptr) {
-                    mDisplays.emplace(displayToken,
-                                      setupNewDisplayDeviceInternal(displayToken,
-                                                                    compositionDisplay, state,
-                                                                    dispSurface, producer));
-                    if (!state.isVirtual()) {
-                        LOG_ALWAYS_FATAL_IF(!displayId);
-                        dispatchDisplayHotplugEvent(displayId->value, true);
-                    }
-
-                    const auto displayDevice = mDisplays[displayToken];
-                    if (displayDevice->isPrimary()) {
-                        mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() *
-                                                                displayDevice->getHeight());
-                    }
-                }
+        for (size_t i = 0; i < curr.size(); i++) {
+            const wp<IBinder>& displayToken = curr.keyAt(i);
+            if (draw.indexOfKey(displayToken) < 0) {
+                processDisplayAdded(displayToken, curr[i]);
             }
         }
     }
@@ -2769,6 +2800,19 @@
 void SurfaceFlinger::updateInputWindowInfo() {
     std::vector<InputWindowInfo> inputHandles;
 
+    // We use a simple caching algorithm here. mInputDirty begins as true,
+    // after we call setInputWindows we set it to false, so
+    // in the future we wont call it again.. We set input dirty to true again
+    // when any layer that hasInput() has a transaction performed on it
+    // or when any parent or relative parent of such a layer has a transaction
+    // performed on it. Not all of these transactions will really result in
+    // input changes but all input changes will spring from these transactions
+    // so the cache is safe but not optimal. It seems like it might be annoyingly
+    // costly to cache and comapre the actual InputWindowHandle vector though.
+    if (!mInputDirty && !mInputWindowCommands.syncInputWindows) {
+        return;
+    }
+
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
         if (layer->hasInput()) {
             // When calculating the screen bounds we ignore the transparent region since it may
@@ -2780,10 +2824,12 @@
     mInputFlinger->setInputWindows(inputHandles,
                                    mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
                                                                          : nullptr);
+
+    mInputDirty = false;
 }
 
 void SurfaceFlinger::commitInputWindowCommands() {
-    mInputWindowCommands = mPendingInputWindowCommands;
+    mInputWindowCommands.merge(mPendingInputWindowCommands);
     mPendingInputWindowCommands.clear();
 }
 
@@ -3058,9 +3104,9 @@
             parent = parentLayer;
         }
 
-        if (mNumLayers >= MAX_LAYERS) {
+        if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
             ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
-                  MAX_LAYERS);
+                  ISurfaceComposer::MAX_LAYERS);
             return NO_MEMORY;
         }
 
@@ -3550,7 +3596,7 @@
         if (layer->setCornerRadius(s.cornerRadius))
             flags |= eTraversalNeeded;
     }
-    if (what & layer_state_t::eBackgroundBlurRadiusChanged) {
+    if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs) {
         if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eLayerStackChanged) {
@@ -3720,10 +3766,6 @@
 
 uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
     uint32_t flags = 0;
-    if (!inputWindowCommands.transferTouchFocusCommands.empty()) {
-        flags |= eTraversalNeeded;
-    }
-
     if (inputWindowCommands.syncInputWindows) {
         flags |= eTraversalNeeded;
     }
@@ -4449,12 +4491,11 @@
     result.append("\n");
 }
 
-LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
-    Mutex::Autolock _l(mStateLock);
-    const auto device = getDefaultDisplayDeviceLocked();
+LayersProto SurfaceFlinger::dumpDrawingStateProto(
+        uint32_t traceFlags, const sp<const DisplayDevice>& displayDevice) const {
     LayersProto layersProto;
     for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
-        layer->writeToProto(layersProto, traceFlags, device);
+        layer->writeToProto(layersProto, traceFlags, displayDevice);
     }
 
     return layersProto;
@@ -4486,7 +4527,10 @@
 
 LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
     LayersProto layersProto;
-    postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
+    postMessageSync(new LambdaMessage([&]() {
+        const auto& displayDevice = getDefaultDisplayDeviceLocked();
+        layersProto = dumpDrawingStateProto(traceFlags, displayDevice);
+    }));
     return layersProto;
 }
 
@@ -5128,7 +5172,7 @@
                 n = data.readInt32();
                 if (n == 1 && !mRefreshRateOverlay) {
                     mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
-                    auto current = mRefreshRateConfigs->getCurrentRefreshRate();
+                    auto& current = mRefreshRateConfigs->getCurrentRefreshRate();
                     mRefreshRateOverlay->changeRefreshRate(current);
                 } else if (n == 0) {
                     mRefreshRateOverlay.reset();
@@ -5177,7 +5221,7 @@
         if (mRefreshRateOverlay) {
             const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
             const bool timerExpired = kernelTimerEnabled && expired;
-            const auto& current = [this]() {
+            const auto& current = [this]() -> const RefreshRate& {
                 std::lock_guard<std::mutex> lock(mActiveConfigLock);
                 if (mDesiredActiveConfigChanged) {
                     return mRefreshRateConfigs->getRefreshRateFromConfigId(
@@ -5758,6 +5802,7 @@
     Mutex::Autolock _l(mStateLock);
 
     mPendingSyncInputWindows = false;
+
     mTransactionCV.broadcast();
 }
 
@@ -5857,7 +5902,7 @@
                                 display->getActiveConfig(), vsyncPeriod);
 
     auto configId = mScheduler->getPreferredConfigId();
-    auto preferredRefreshRate = configId
+    auto& preferredRefreshRate = configId
             ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
             // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
             : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 83f0131..44e18a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -42,6 +42,7 @@
 #include <system/graphics.h>
 #include <ui/FenceTime.h>
 #include <ui/PixelFormat.h>
+#include <ui/Size.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
@@ -225,6 +226,11 @@
     // FramebufferSurface
     static int64_t maxFrameBufferAcquiredBuffers;
 
+    // Controls the maximum width and height in pixels that the graphics pipeline can support for
+    // GPU fallback composition. For example, 8k devices with 4k GPUs, or 4k devices with 2k GPUs.
+    static uint32_t maxGraphicsWidth;
+    static uint32_t maxGraphicsHeight;
+
     // Indicate if a device has wide color gamut display. This is typically
     // found on devices with wide color gamut (e.g. Display-P3) display.
     static bool hasWideColorDisplay;
@@ -351,7 +357,6 @@
     // every half hour.
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
 
-    static const size_t MAX_LAYERS = 4096;
     static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
 
 protected:
@@ -815,9 +820,14 @@
             const wp<IBinder>& displayToken,
             std::shared_ptr<compositionengine::Display> compositionDisplay,
             const DisplayDeviceState& state,
-            const sp<compositionengine::DisplaySurface>& dispSurface,
+            const sp<compositionengine::DisplaySurface>& displaySurface,
             const sp<IGraphicBufferProducer>& producer);
     void processDisplayChangesLocked();
+    void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state);
+    void processDisplayRemoved(const wp<IBinder>& displayToken);
+    void processDisplayChanged(const wp<IBinder>& displayToken,
+                               const DisplayDeviceState& currentState,
+                               const DisplayDeviceState& drawingState);
     void processDisplayHotplugEventsLocked();
 
     void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
@@ -918,7 +928,8 @@
     void dumpDisplayIdentificationData(std::string& result) const;
     void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
     void dumpWideColorInfo(std::string& result) const;
-    LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+    LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL,
+                                      const sp<const DisplayDevice>& displayDevice = nullptr) const;
     void dumpOffscreenLayersProto(LayersProto& layersProto,
                                   uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
     // Dumps state from HW Composer
@@ -976,7 +987,7 @@
 
     // Can't be unordered_set because wp<> isn't hashable
     std::set<wp<IBinder>> mGraphicBufferProducerList;
-    size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
+    size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS;
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved = false;
@@ -1049,8 +1060,10 @@
     const std::shared_ptr<TimeStats> mTimeStats;
     const std::unique_ptr<FrameTracer> mFrameTracer;
     bool mUseHwcVirtualDisplays = false;
+    // If blurs should be enabled on this device.
+    bool mSupportsBlur = false;
     // Disable blurs, for debugging
-    bool mEnableBlurs = false;
+    std::atomic<bool> mDisableBlurs = false;
     // If blurs are considered expensive and should require high GPU frequency.
     bool mBlursAreExpensive = false;
     std::atomic<uint32_t> mFrameMissedCount = 0;
@@ -1124,6 +1137,10 @@
 
     // to linkToDeath
     sp<IBinder> mWindowManager;
+    // We want to avoid multiple calls to BOOT_FINISHED as they come in on
+    // different threads without a lock and could trigger unsynchronized writes to
+    // to mWindowManager or mInputFlinger
+    std::atomic<bool> mBootFinished = false;
 
     std::unique_ptr<dvr::VrFlinger> mVrFlinger;
     std::atomic<bool> mVrFlingerRequestsDisplay = false;
@@ -1236,6 +1253,11 @@
     // janky frames there are.
     nsecs_t mMissedFrameJankStart = 0;
     int32_t mMissedFrameJankCount = 0;
+
+    // See updateInputWindowInfo() for details
+    std::atomic<bool> mInputDirty = true;
+    void dirtyInput() { mInputDirty = true; }
+    bool inputDirty() { return mInputDirty; }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index f3352a5..9d78702 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -70,6 +70,22 @@
             defaultValue);
 }
 
+int32_t max_graphics_width(int32_t defaultValue) {
+    auto temp = SurfaceFlingerProperties::max_graphics_width();
+    if (temp.has_value()) {
+        return *temp;
+    }
+    return defaultValue;
+}
+
+int32_t max_graphics_height(int32_t defaultValue) {
+    auto temp = SurfaceFlingerProperties::max_graphics_height();
+    if (temp.has_value()) {
+        return *temp;
+    }
+    return defaultValue;
+}
+
 bool has_wide_color_display(bool defaultValue) {
     auto temp = SurfaceFlingerProperties::has_wide_color_display();
     if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 12c711a..c63adfe 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -37,6 +37,9 @@
 
 int64_t max_frame_buffer_acquired_buffers(int64_t defaultValue);
 
+int32_t max_graphics_width(int32_t defaultValue);
+int32_t max_graphics_height(int32_t defaultValue);
+
 bool has_wide_color_display(bool defaultValue);
 
 bool running_without_sync_framework(bool defaultValue);
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 1f9d46c..5b3cd69 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -524,11 +524,11 @@
     deletion->set_id(getLayerId(layer));
 }
 
-void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, const sp<const Layer>& layer,
+void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, int32_t layerId,
         uint32_t width, uint32_t height, uint64_t frameNumber)
 {
     BufferUpdate* update(increment->mutable_buffer_update());
-    update->set_id(getLayerId(layer));
+    update->set_id(layerId);
     update->set_w(width);
     update->set_h(height);
     update->set_frame_number(frameNumber);
@@ -644,15 +644,22 @@
     addSurfaceDeletionLocked(createTraceIncrementLocked(), layer);
 }
 
-void SurfaceInterceptor::saveBufferUpdate(const sp<const Layer>& layer, uint32_t width,
+/**
+ * Here we pass the layer by ID instead of by sp<> since this is called without
+ * holding the state-lock from a Binder thread. If we required the caller
+ * to pass 'this' by sp<> the temporary sp<> constructed could end up
+ * being the last reference and we might accidentally destroy the Layer
+ * from this binder thread.
+ */
+void SurfaceInterceptor::saveBufferUpdate(int32_t layerId, uint32_t width,
         uint32_t height, uint64_t frameNumber)
 {
-    if (!mEnabled || layer == nullptr) {
+    if (!mEnabled) {
         return;
     }
     ATRACE_CALL();
     std::lock_guard<std::mutex> protoGuard(mTraceMutex);
-    addBufferUpdateLocked(createTraceIncrementLocked(), layer, width, height, frameNumber);
+    addBufferUpdateLocked(createTraceIncrementLocked(), layerId, width, height, frameNumber);
 }
 
 void SurfaceInterceptor::saveVSyncEvent(nsecs_t timestamp) {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index a665f62..896bdcc 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -67,7 +67,7 @@
     // Intercept surface data
     virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
     virtual void saveSurfaceDeletion(const sp<const Layer>& layer) = 0;
-    virtual void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+    virtual void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height,
                                   uint64_t frameNumber) = 0;
 
     // Intercept display data
@@ -102,7 +102,7 @@
     // Intercept surface data
     void saveSurfaceCreation(const sp<const Layer>& layer) override;
     void saveSurfaceDeletion(const sp<const Layer>& layer) override;
-    void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+    void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height,
                           uint64_t frameNumber) override;
 
     // Intercept display data
@@ -130,7 +130,7 @@
     Increment* createTraceIncrementLocked();
     void addSurfaceCreationLocked(Increment* increment, const sp<const Layer>& layer);
     void addSurfaceDeletionLocked(Increment* increment, const sp<const Layer>& layer);
-    void addBufferUpdateLocked(Increment* increment, const sp<const Layer>& layer, uint32_t width,
+    void addBufferUpdateLocked(Increment* increment, int32_t layerId, uint32_t width,
             uint32_t height, uint64_t frameNumber);
     void addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp);
     void addDisplayCreationLocked(Increment* increment, const DisplayDeviceState& info);
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index c5556ec..20c8d7a 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -45,19 +45,21 @@
 }
 
 void SurfaceTracing::addFirstEntry() {
+    const auto displayDevice = mFlinger.getDefaultDisplayDevice();
     LayersTraceProto entry;
     {
         std::scoped_lock lock(mSfLock);
-        entry = traceLayersLocked("tracing.enable");
+        entry = traceLayersLocked("tracing.enable", displayDevice);
     }
     addTraceToBuffer(entry);
 }
 
 LayersTraceProto SurfaceTracing::traceWhenNotified() {
+    const auto displayDevice = mFlinger.getDefaultDisplayDevice();
     std::unique_lock<std::mutex> lock(mSfLock);
     mCanStartTrace.wait(lock);
     android::base::ScopedLockAssertion assumeLock(mSfLock);
-    LayersTraceProto entry = traceLayersLocked(mWhere);
+    LayersTraceProto entry = traceLayersLocked(mWhere, displayDevice);
     lock.unlock();
     return entry;
 }
@@ -160,13 +162,14 @@
     mTraceFlags = flags;
 }
 
-LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
+LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where,
+                                                   const sp<const DisplayDevice>& displayDevice) {
     ATRACE_CALL();
 
     LayersTraceProto entry;
     entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
     entry.set_where(where);
-    LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
+    LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags, displayDevice));
     mFlinger.dumpOffscreenLayersProto(layers);
     entry.mutable_layers()->Swap(&layers);
 
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 3c24881..4b9f777 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -16,17 +16,19 @@
 
 #pragma once
 
+#include <android-base/thread_annotations.h>
 #include <layerproto/LayerProtoHeader.h>
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 
-#include <android-base/thread_annotations.h>
 #include <condition_variable>
 #include <memory>
 #include <mutex>
 #include <queue>
 #include <thread>
 
+#include "DisplayDevice.h"
+
 using namespace android::surfaceflinger;
 
 namespace android {
@@ -85,13 +87,15 @@
     void mainLoop();
     void addFirstEntry();
     LayersTraceProto traceWhenNotified();
-    LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+    LayersTraceProto traceLayersLocked(const char* where,
+                                       const sp<const DisplayDevice>& displayDevice)
+            REQUIRES(mSfLock);
 
     // Returns true if trace is enabled.
     bool addTraceToBuffer(LayersTraceProto& entry);
     void writeProtoFileLocked() REQUIRES(mTraceLock);
 
-    const SurfaceFlinger& mFlinger;
+    SurfaceFlinger& mFlinger;
     status_t mLastErr = NO_ERROR;
     std::thread mThread;
     std::condition_variable mCanStartTrace;
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 155f718..cfc301b 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -67,6 +67,26 @@
     prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
 }
 
+# Controls the maximum width in pixels that the graphics pipeline can support for GPU fallback
+# composition. For example, 8k displays with 4k GPUs, or 4k displays with 2k GPUs.
+prop {
+    api_name: "max_graphics_width"
+    type: Integer
+    scope: System
+    access: Readonly
+    prop_name: "ro.surface_flinger.max_graphics_width"
+}
+
+# Controls the maximum height in pixels that the graphics pipeline can support for GPU fallback
+# composition. For example, 8k displays with 4k GPUs, or 4k displays with 2k GPUs.
+prop {
+    api_name: "max_graphics_height"
+    type: Integer
+    scope: System
+    access: Readonly
+    prop_name: "ro.surface_flinger.max_graphics_height"
+}
+
 # hasWideColorDisplay indicates that the device has
 # or can support a wide-color display, e.g. color space
 # greater than sRGB. Typical display may have same
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index e62c127..ba60a7d 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -62,6 +62,16 @@
     prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
   }
   prop {
+    api_name: "max_graphics_height"
+    type: Integer
+    prop_name: "ro.surface_flinger.max_graphics_height"
+  }
+  prop {
+    api_name: "max_graphics_width"
+    type: Integer
+    prop_name: "ro.surface_flinger.max_graphics_width"
+  }
+  prop {
     api_name: "max_virtual_display_dimension"
     type: Long
     prop_name: "ro.surface_flinger.max_virtual_display_dimension"
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index a023367..c2ddfce 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <functional>
+#include <string_view>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -124,6 +127,10 @@
     return DisplayIdentificationData(bytes, bytes + N - 1);
 }
 
+uint32_t hash(const char* str) {
+    return static_cast<uint32_t>(std::hash<std::string_view>()(str));
+}
+
 } // namespace
 
 const DisplayIdentificationData& getInternalEdid() {
@@ -173,7 +180,8 @@
     EXPECT_EQ(0x4ca3u, edid->manufacturerId);
     EXPECT_STREQ("SEC", edid->pnpId.data());
     // ASCII text should be used as fallback if display name and serial number are missing.
-    EXPECT_EQ("121AT11-801", edid->displayName);
+    EXPECT_EQ(hash("121AT11-801"), edid->modelHash);
+    EXPECT_TRUE(edid->displayName.empty());
     EXPECT_EQ(12610, edid->productId);
     EXPECT_EQ(21, edid->manufactureOrModelYear);
     EXPECT_EQ(0, edid->manufactureWeek);
@@ -182,6 +190,7 @@
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x22f0u, edid->manufacturerId);
     EXPECT_STREQ("HWP", edid->pnpId.data());
+    EXPECT_EQ(hash("HP ZR30w"), edid->modelHash);
     EXPECT_EQ("HP ZR30w", edid->displayName);
     EXPECT_EQ(10348, edid->productId);
     EXPECT_EQ(22, edid->manufactureOrModelYear);
@@ -191,6 +200,7 @@
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x4c2du, edid->manufacturerId);
     EXPECT_STREQ("SAM", edid->pnpId.data());
+    EXPECT_EQ(hash("SAMSUNG"), edid->modelHash);
     EXPECT_EQ("SAMSUNG", edid->displayName);
     EXPECT_EQ(2302, edid->productId);
     EXPECT_EQ(21, edid->manufactureOrModelYear);
@@ -200,6 +210,7 @@
     ASSERT_TRUE(edid);
     EXPECT_EQ(13481, edid->manufacturerId);
     EXPECT_STREQ("MEI", edid->pnpId.data());
+    EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash);
     EXPECT_EQ("Panasonic-TV", edid->displayName);
     EXPECT_EQ(41622, edid->productId);
     EXPECT_EQ(29, edid->manufactureOrModelYear);
@@ -209,6 +220,7 @@
     ASSERT_TRUE(edid);
     EXPECT_EQ(8355, edid->manufacturerId);
     EXPECT_STREQ("HEC", edid->pnpId.data());
+    EXPECT_EQ(hash("Hisense"), edid->modelHash);
     EXPECT_EQ("Hisense", edid->displayName);
     EXPECT_EQ(0, edid->productId);
     EXPECT_EQ(29, edid->manufactureOrModelYear);
@@ -218,6 +230,7 @@
     ASSERT_TRUE(edid);
     EXPECT_EQ(3724, edid->manufacturerId);
     EXPECT_STREQ("CTL", edid->pnpId.data());
+    EXPECT_EQ(hash("LP2361"), edid->modelHash);
     EXPECT_EQ("LP2361", edid->displayName);
     EXPECT_EQ(9373, edid->productId);
     EXPECT_EQ(23, edid->manufactureOrModelYear);
@@ -234,13 +247,15 @@
     auto edid = parseEdid(data);
     ASSERT_TRUE(edid);
     // Serial number should be used as fallback if display name is invalid.
-    EXPECT_EQ("CN4202137Q", edid->displayName);
+    const auto modelHash = hash("CN4202137Q");
+    EXPECT_EQ(modelHash, edid->modelHash);
+    EXPECT_TRUE(edid->displayName.empty());
 
     // Parsing should succeed even if EDID is truncated.
     data.pop_back();
     edid = parseEdid(data);
     ASSERT_TRUE(edid);
-    EXPECT_EQ("CN4202137Q", edid->displayName);
+    EXPECT_EQ(modelHash, edid->modelHash);
 }
 
 TEST(DisplayIdentificationTest, getPnpId) {
@@ -278,7 +293,7 @@
         ASSERT_TRUE(displayIdInfo);
         ASSERT_TRUE(displayIdInfo->deviceProductInfo);
         const auto& info = *displayIdInfo->deviceProductInfo;
-        EXPECT_STREQ("121AT11-801", info.name.data());
+        EXPECT_STREQ("", info.name.data());
         EXPECT_STREQ("SEC", info.manufacturerPnpId.data());
         EXPECT_STREQ("12610", info.productId.data());
         ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index e7e7f66..dd04076 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -21,6 +21,7 @@
 #include <log/log.h>
 #include <thread>
 
+#include "../../Scheduler/RefreshRateConfigs.h"
 #include "DisplayHardware/HWC2.h"
 #include "Scheduler/RefreshRateConfigs.h"
 
@@ -93,8 +94,8 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto minRate = refreshRateConfigs->getMinRefreshRate();
-    const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate = refreshRateConfigs->getMinRefreshRate();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
 
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
     ASSERT_EQ(expectedDefaultConfig, minRate);
@@ -102,8 +103,8 @@
                                              90};
     ASSERT_EQ(expectedPerformanceConfig, performanceRate);
 
-    const auto minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    const auto& minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
     ASSERT_EQ(minRateByPolicy, minRate);
     ASSERT_EQ(performanceRateByPolicy, performanceRate);
 }
@@ -115,10 +116,10 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
-    const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
     ASSERT_EQ(expectedDefaultConfig, minRate);
@@ -128,8 +129,8 @@
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
 
-    const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_1, "90fps",
                                              90};
@@ -145,8 +146,8 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    auto& performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
     ASSERT_EQ(expectedDefaultConfig, minRate);
@@ -156,8 +157,8 @@
 
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
 
-    auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
     ASSERT_EQ(expectedDefaultConfig, minRate60);
     ASSERT_EQ(expectedDefaultConfig, performanceRate60);
 }
@@ -169,19 +170,19 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
     {
-        auto current = refreshRateConfigs->getCurrentRefreshRate();
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.configId, HWC_CONFIG_ID_60);
     }
 
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
     {
-        auto current = refreshRateConfigs->getCurrentRefreshRate();
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
     }
 
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
     {
-        auto current = refreshRateConfigs->getCurrentRefreshRate();
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
     }
 }
@@ -248,6 +249,7 @@
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
@@ -263,16 +265,17 @@
     auto layers = std::vector<LayerRequirement>{};
     EXPECT_EQ(expected72Config,
               refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
-                                                             false));
+                                                             false, &ignored));
 
     // Current refresh rate can always be changed.
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
     EXPECT_EQ(expected60Config,
               refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
-                                                             false));
+                                                             false, &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -288,134 +291,163 @@
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Heuristic";
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     lr.name = "45Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     lr.name = "30Hz Heuristic";
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     lr.name = "24Hz Heuristic";
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.name = "";
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
@@ -432,35 +464,43 @@
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
              {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -486,24 +526,28 @@
     lr2.desiredRefreshRate = 60.0f;
     lr2.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 48.0f;
     lr2.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 48.0f;
     lr2.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
              {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -531,7 +575,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
     EXPECT_EQ(expected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -540,7 +585,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
     EXPECT_EQ(expected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -549,7 +595,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "60Hz ExplicitDefault";
     EXPECT_EQ(expected120Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -558,7 +605,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -567,7 +615,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitDefault;
@@ -576,7 +625,8 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::Heuristic;
@@ -585,7 +635,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -594,7 +645,8 @@
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.desiredRefreshRate = 24.0f;
     lr1.vote = LayerVoteType::ExplicitDefault;
@@ -603,10 +655,12 @@
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.name = "90Hz ExplicitExactOrMultiple";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}};
@@ -621,35 +675,43 @@
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(expected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     EXPECT_EQ(expected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
              {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -669,57 +731,71 @@
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
     EXPECT_EQ(expected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 90.0f;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Heuristic";
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 45.0f;
     lr.name = "45Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 30.0f;
     lr.name = "30Hz Heuristic";
     EXPECT_EQ(expected30Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     lr.name = "24Hz Heuristic";
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+                                                             &ignored));
 
     lr.desiredRefreshRate = 24.0f;
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr.name = "24Hz ExplicitExactOrMultiple";
     EXPECT_EQ(expected72Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
              {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -739,48 +815,56 @@
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::Max;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 24.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Max;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Max;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Heuristic;
     lr1.desiredRefreshRate = 15.0f;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Heuristic;
     lr1.desiredRefreshRate = 30.0f;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 45.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -798,7 +882,8 @@
     for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
         lr.desiredRefreshRate = fps;
         const auto& refreshRate =
-                refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false);
+                refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                               &ignored);
         printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
         EXPECT_EQ(expected60Config, refreshRate);
     }
@@ -833,6 +918,7 @@
 }
 
 TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Explicit) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -852,21 +938,24 @@
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 90.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.desiredRefreshRate = 90.0f;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::Heuristic;
     lr1.desiredRefreshRate = 90.0f;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.desiredRefreshRate = 60.0f;
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, testInPolicy) {
@@ -880,6 +969,7 @@
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -897,13 +987,15 @@
     for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
         lr.desiredRefreshRate = fps;
         const auto& refreshRate =
-                refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false);
+                refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                               &ignored);
         printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
         EXPECT_EQ(expected90Config, refreshRate);
     }
 }
 
 TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -925,7 +1017,8 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -934,7 +1027,8 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz ExplicitDefault";
     EXPECT_EQ(expected60Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
@@ -942,7 +1036,8 @@
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 30.0f;
@@ -951,7 +1046,8 @@
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz Heuristic";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 30.0f;
@@ -959,10 +1055,12 @@
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
     EXPECT_EQ(expected90Config,
-              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+              refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+                                                             &ignored));
 }
 
 TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
+    bool ignored;
     std::vector<RefreshRateConfigs::InputConfig> configs{
             {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
              {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -982,28 +1080,32 @@
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::NoVote;
     lr2.name = "NoVote";
-    EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+    EXPECT_EQ(expected60Config,
+              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::NoVote;
     lr2.name = "NoVote";
-    EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true));
+    EXPECT_EQ(expected90Config,
+              refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
-    EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true));
+    EXPECT_EQ(expected90Config,
+              refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.desiredRefreshRate = 60.0f;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
-    EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+    EXPECT_EQ(expected90Config,
+              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
 
     // The other layer starts to provide buffers
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -1012,7 +1114,108 @@
     lr2.vote = LayerVoteType::Heuristic;
     lr2.desiredRefreshRate = 90.0f;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+    EXPECT_EQ(expected90Config,
+              refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+}
+
+TEST_F(RefreshRateConfigsTest, touchConsidered) {
+    bool touchConsidered;
+    std::vector<RefreshRateConfigs::InputConfig> configs{
+            {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+             {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    refreshRateConfigs->getRefreshRateForContentV2({}, false, &touchConsidered);
+    EXPECT_EQ(false, touchConsidered);
+
+    refreshRateConfigs->getRefreshRateForContentV2({}, true, &touchConsidered);
+    EXPECT_EQ(true, touchConsidered);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "NoVote";
+    refreshRateConfigs->getRefreshRateForContentV2(layers, true, &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);
+    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);
+    EXPECT_EQ(true, touchConsidered);
+
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "NoVote";
+    refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+    EXPECT_EQ(false, touchConsidered);
+}
+
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) {
+    bool ignored;
+    std::vector<RefreshRateConfigs::InputConfig> configs{
+            {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+             {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+             {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
+             {HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
+
+    auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/
+                                                                   HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    // Prepare a table with the vote and the expected refresh rate
+    const std::vector<std::pair<float, float>> testCases = {
+            {130, 120}, {120, 120}, {119, 120}, {110, 120},
+
+            {100, 90},  {90, 90},   {89, 90},
+
+            {80, 72},   {73, 72},   {72, 72},   {71, 72},   {70, 72},
+
+            {65, 60},   {60, 60},   {59, 60},   {58, 60},
+
+            {55, 90},   {50, 90},   {45, 90},
+
+            {42, 120},  {40, 120},  {39, 120},
+
+            {37, 72},   {36, 72},   {35, 72},
+
+            {30, 60},
+    };
+
+    for (const auto& test : testCases) {
+        lr.vote = LayerVoteType::ExplicitDefault;
+        lr.desiredRefreshRate = test.first;
+
+        std::stringstream ss;
+        ss << "ExplicitDefault " << test.first << " fps";
+        lr.name = ss.str();
+
+        const auto& refreshRate =
+                refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored);
+        EXPECT_FLOAT_EQ(refreshRate.fps, test.second)
+                << "Expecting " << test.first << "fps => " << test.second << "Hz";
+    }
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index 458b2f3..5beee1c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -39,7 +39,7 @@
                       const Vector<DisplayState>&, uint32_t));
     MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
     MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
-    MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t));
+    MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));
     MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
     MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
     MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));