Merge "Remove __ANDROID_API__ #if checks." into sc-dev
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 65fc46e..4dfd1d0 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1130,23 +1130,6 @@
     return true;
 }
 
-// Updates the access times of out_oat_path based on those from apk_path.
-void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
-    struct stat input_stat;
-    memset(&input_stat, 0, sizeof(input_stat));
-    if (stat(apk_path, &input_stat) != 0) {
-        PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
-        return;
-    }
-
-    struct utimbuf ut;
-    ut.actime = input_stat.st_atime;
-    ut.modtime = input_stat.st_mtime;
-    if (utime(out_oat_path, &ut) != 0) {
-        PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
-    }
-}
-
 // Runs (execv) dexoptanalyzer on the given arguments.
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
@@ -1843,8 +1826,6 @@
         }
     }
 
-    update_out_oat_access_times(dex_path, out_oat.path().c_str());
-
     // We've been successful, don't delete output.
     out_oat.DisableCleanup();
     out_vdex.DisableCleanup();
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index c6f656b..79aab82 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -50,11 +50,10 @@
         CornerRadiusChange          corner_radius           = 16;
         ReparentChange              reparent                = 17;
         RelativeParentChange        relative_parent         = 18;
-        DetachChildrenChange        detach_children         = 19;
-        ReparentChildrenChange      reparent_children       = 20;
-        BackgroundBlurRadiusChange  background_blur_radius  = 21;
-        ShadowRadiusChange          shadow_radius           = 22;
-        BlurRegionsChange           blur_regions            = 23;
+        ReparentChildrenChange      reparent_children       = 19;
+        BackgroundBlurRadiusChange  background_blur_radius  = 20;
+        ShadowRadiusChange          shadow_radius           = 21;
+        BlurRegionsChange           blur_regions            = 22;
     }
 }
 
@@ -200,10 +199,6 @@
     required int32 z = 2;
 }
 
-message DetachChildrenChange {
-    required bool detach_children = 1;
-}
-
 message ShadowRadiusChange {
     required float radius = 1;
 }
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 5849212..58d6582 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -417,9 +417,6 @@
             case SurfaceChange::SurfaceChangeCase::kRelativeParent:
                 setRelativeParentChange(transaction, change.id(), change.relative_parent());
                 break;
-            case SurfaceChange::SurfaceChangeCase::kDetachChildren:
-                setDetachChildrenChange(transaction, change.id(), change.detach_children());
-                break;
             case SurfaceChange::SurfaceChangeCase::kShadowRadius:
                 setShadowRadiusChange(transaction, change.id(), change.shadow_radius());
                 break;
@@ -713,11 +710,6 @@
     t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()], c.z());
 }
 
-void Replayer::setDetachChildrenChange(SurfaceComposerClient::Transaction& t,
-        layer_id id, const DetachChildrenChange& c) {
-    t.detachChildren(mLayers[id]);
-}
-
 void Replayer::setReparentChildrenChange(SurfaceComposerClient::Transaction& t,
         layer_id id, const ReparentChildrenChange& c) {
     if (mLayers.count(c.parent_id()) == 0 || mLayers[c.parent_id()] == nullptr) {
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index a22262a..324d591 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -116,8 +116,6 @@
             layer_id id, const ReparentChange& c);
     void setRelativeParentChange(SurfaceComposerClient::Transaction& t,
             layer_id id, const RelativeParentChange& c);
-    void setDetachChildrenChange(SurfaceComposerClient::Transaction& t,
-            layer_id id, const DetachChildrenChange& c);
     void setReparentChildrenChange(SurfaceComposerClient::Transaction& t,
             layer_id id, const ReparentChildrenChange& c);
     void setShadowRadiusChange(SurfaceComposerClient::Transaction& t,
diff --git a/data/etc/android.hardware.keystore.limited_use_key.xml b/data/etc/android.hardware.keystore.limited_use_key.xml
new file mode 100644
index 0000000..5217086
--- /dev/null
+++ b/data/etc/android.hardware.keystore.limited_use_key.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Feature for devices with KeyMint that can enforce limited use key
+     in hardware with any max usage count (including count equals to 1). -->
+<permissions>
+    <feature name="android.hardware.keystore.limited_use_key" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/android.hardware.keystore.single_use_key.xml b/data/etc/android.hardware.keystore.single_use_key.xml
new file mode 100644
index 0000000..40e80aa
--- /dev/null
+++ b/data/etc/android.hardware.keystore.single_use_key.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<!-- Feature for devices with KeyMint that only can enforce limited use key
+     in hardware with max usage count equals to 1. -->
+<permissions>
+    <feature name="android.hardware.keystore.single_use_key" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index cc0ee82..adfd6e2 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -47,6 +47,12 @@
     <feature name="android.software.secure_lock_screen" />
     <feature name="android.software.input_methods" />
 
+
+    <!-- Feature to support device admins -->
+    <!-- TODO(b/178412797): not fully supported yet, CTS tests are still
+         failing. -->
+    <feature name="android.software.device_admin" />
+
     <!-- devices with GPS must include android.hardware.location.gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
          android.hardware.camera.autofocus.xml or
diff --git a/include/android/input.h b/include/android/input.h
index b5d399e..b70d424 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -856,8 +856,10 @@
     AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
     /** joystick */
     AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
+    /** HDMI */
+    AINPUT_SOURCE_HDMI = 0x02000000 | AINPUT_SOURCE_CLASS_BUTTON,
     /** sensor */
-    AINPUT_SOURCE_SENSOR = 0x02000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
+    AINPUT_SOURCE_SENSOR = 0x04000000 | AINPUT_SOURCE_UNKNOWN,
     /** rotary encoder */
     AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE,
 
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 23692e9..2bd7bd2 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -213,6 +213,9 @@
     inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
     inline bool hasVibrator() const { return mHasVibrator; }
 
+    inline void setHasBattery(bool hasBattery) { mHasBattery = hasBattery; }
+    inline bool hasBattery() const { return mHasBattery; }
+
     inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; }
     inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; }
 
@@ -239,6 +242,7 @@
     int32_t mKeyboardType;
     std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
     bool mHasVibrator;
+    bool mHasBattery;
     bool mHasButtonUnderPad;
     bool mHasSensor;
 
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 454fbd0..3c90681 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -597,13 +597,6 @@
         return STATUS_INVALID_OPERATION;
     }
 
-    if (!binder->isRemote()) {
-        LOG(WARNING) << "A binder object at " << binder
-                     << " is being transacted on, however, this object is in the same process as "
-                        "its proxy. Transacting with this binder is expensive compared to just "
-                        "calling the corresponding functionality in the same process.";
-    }
-
     *in = new AParcel(binder);
     status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
     binder_status_t ret = PruneStatusT(status);
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 2ae13f4..2bf3d03 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -25,7 +25,6 @@
 use binder::parcel::ParcelFileDescriptor;
 
 use std::ffi::{c_void, CStr, CString};
-use std::panic::{self, AssertUnwindSafe};
 use std::sync::Once;
 
 #[allow(
@@ -73,22 +72,9 @@
 
 impl ReadParcelTest for () {}
 
-fn on_transact(
-    _service: &dyn ReadParcelTest,
-    code: TransactionCode,
-    parcel: &Parcel,
-    reply: &mut Parcel,
-) -> Result<()> {
-    panic::catch_unwind(AssertUnwindSafe(|| transact_inner(code, parcel, reply))).unwrap_or_else(
-        |e| {
-            eprintln!("Failure in Rust: {:?}", e.downcast_ref::<String>());
-            Err(StatusCode::FAILED_TRANSACTION)
-        },
-    )
-}
-
 #[allow(clippy::float_cmp)]
-fn transact_inner(code: TransactionCode, parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
+fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode,
+               parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
     match code {
         bindings::Transaction_TEST_BOOL => {
             assert_eq!(parcel.read::<bool>()?, true);
@@ -296,7 +282,7 @@
             ))?;
         }
         bindings::Transaction_TEST_FAIL => {
-            panic!("Testing expected failure");
+            return Err(StatusCode::FAILED_TRANSACTION)
         }
         _ => return Err(StatusCode::UNKNOWN_TRANSACTION),
     }
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 462f0db..7e9bb7d 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -155,10 +155,14 @@
     return true;
 }
 
-static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+static int retrieveProgramFd(const std::string &eventType, const std::string &eventName) {
     std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
                                     eventType.c_str(), eventName.c_str());
-    int prog_fd = retrieveProgram(path.c_str());
+    return retrieveProgram(path.c_str());
+}
+
+static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+    int prog_fd = retrieveProgramFd(eventType, eventName);
     if (prog_fd < 0) return false;
     return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
 }
@@ -174,6 +178,17 @@
     return {};
 }
 
+// Check if tracking is expected to work without activating it.
+bool isTrackingUidTimesSupported() {
+    auto freqs = getCpuFreqs();
+    if (!freqs || freqs->empty()) return false;
+    if (gTracking) return true;
+    if (retrieveProgramFd("sched", "sched_switch") < 0) return false;
+    if (retrieveProgramFd("power", "cpu_frequency") < 0) return false;
+    if (retrieveProgramFd("sched", "sched_process_free") < 0) return false;
+    return true;
+}
+
 // Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
 // Returns true on success, false otherwise.
 // Tracking is active only once a live process has successfully called this function; if the calling
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 46de669..4145374 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -22,6 +22,7 @@
 namespace android {
 namespace bpf {
 
+bool isTrackingUidTimesSupported();
 bool startTrackingUidTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index d25b2e9..2112b10 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -40,6 +40,11 @@
 
 using std::vector;
 
+TEST(TimeInStateTest, IsTrackingSupported) {
+    isTrackingUidTimesSupported();
+    SUCCEED();
+}
+
 TEST(TimeInStateTest, TotalTimeInState) {
     auto times = getTotalCpuFreqTimes();
     ASSERT_TRUE(times.has_value());
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 143fa13..8a82c2a 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -53,7 +53,6 @@
 
 /* list of hal interface to dump containing process during native dumps */
 static const char* hal_interfaces_to_dump[] {
-        "android.hardware.audio@2.0::IDevicesFactory",
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 38ae353..fa5044c 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -49,6 +49,7 @@
 
     srcs: [
         ":framework_native_aidl",
+        ":inputconstants_aidl",
         ":libgui_aidl",
         ":libgui_bufferqueue_sources",
 
@@ -62,6 +63,7 @@
         "DebugEGLImageTracker.cpp",
         "DisplayEventDispatcher.cpp",
         "DisplayEventReceiver.cpp",
+        "FrameTimelineInfo.cpp",
         "GLConsumer.cpp",
         "IConsumerListener.cpp",
         "IDisplayEventConnection.cpp",
@@ -154,6 +156,7 @@
     defaults: ["libgui_bufferqueue-defaults"],
 
     srcs: [
+        ":inputconstants_aidl",
         ":libgui_aidl",
         ":libgui_bufferqueue_sources",
     ],
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 42d2895..c62d9ad 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -370,9 +370,9 @@
     }
     t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
 
-    if (!mNextFrameTimelineVsyncIdQueue.empty()) {
-        t->setFrameTimelineVsync(mSurfaceControl, mNextFrameTimelineVsyncIdQueue.front());
-        mNextFrameTimelineVsyncIdQueue.pop();
+    if (!mNextFrameTimelineInfoQueue.empty()) {
+        t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front());
+        mNextFrameTimelineInfoQueue.pop();
     }
 
     if (mAutoRefresh != bufferItem.mAutoRefresh) {
@@ -534,8 +534,8 @@
         return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless);
     }
 
-    status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override {
-        return mBbq->setFrameTimelineVsync(frameTimelineVsyncId);
+    status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override {
+        return mBbq->setFrameTimelineInfo(frameTimelineInfo);
     }
 };
 
@@ -549,9 +549,9 @@
     return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply();
 }
 
-status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
+status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) {
     std::unique_lock _lock{mMutex};
-    mNextFrameTimelineVsyncIdQueue.push(frameTimelineVsyncId);
+    mNextFrameTimelineInfoQueue.push(frameTimelineInfo);
     return OK;
 }
 
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index c6c9a8f..2ad484a 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,7 +36,9 @@
 DisplayEventDispatcher::DisplayEventDispatcher(
         const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
         ISurfaceComposer::EventRegistrationFlags eventRegistration)
-      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
+      : mLooper(looper),
+        mReceiver(vsyncSource, eventRegistration),
+        mVsyncState(VsyncState::Unregistered) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -66,26 +68,37 @@
 }
 
 status_t DisplayEventDispatcher::scheduleVsync() {
-    if (!mWaitingForVsync) {
-        ALOGV("dispatcher %p ~ Scheduling vsync.", this);
+    switch (mVsyncState) {
+        case VsyncState::Unregistered: {
+            ALOGV("dispatcher %p ~ Scheduling vsync.", this);
 
-        // Drain all pending events.
-        nsecs_t vsyncTimestamp;
-        PhysicalDisplayId vsyncDisplayId;
-        uint32_t vsyncCount;
-        VsyncEventData vsyncEventData;
-        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
-            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
-                  ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
+            // Drain all pending events.
+            nsecs_t vsyncTimestamp;
+            PhysicalDisplayId vsyncDisplayId;
+            uint32_t vsyncCount;
+            VsyncEventData vsyncEventData;
+            if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount,
+                                     &vsyncEventData)) {
+                ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
+                      this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
+            }
+
+            status_t status = mReceiver.setVsyncRate(1);
+            if (status) {
+                ALOGW("Failed to set vsync rate, status=%d", status);
+                return status;
+            }
+
+            mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
+            break;
         }
-
-        status_t status = mReceiver.requestNextVsync();
-        if (status) {
-            ALOGW("Failed to request next vsync, status=%d", status);
-            return status;
+        case VsyncState::Registered: {
+            mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
+            break;
         }
-
-        mWaitingForVsync = true;
+        case VsyncState::RegisteredAndWaitingForVsync: {
+            break;
+        }
     }
     return OK;
 }
@@ -123,8 +136,23 @@
               ", displayId=%s, count=%d, vsyncId=%" PRId64,
               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
               vsyncEventData.id);
-        mWaitingForVsync = false;
-        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
+        switch (mVsyncState) {
+            case VsyncState::Unregistered:
+                ALOGW("Received unexpected VSYNC event");
+                break;
+            case VsyncState::RegisteredAndWaitingForVsync:
+                mVsyncState = VsyncState::Registered;
+                dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
+                break;
+            case VsyncState::Registered:
+                status_t status = mReceiver.setVsyncRate(0);
+                if (status) {
+                    ALOGW("Failed to reset vsync rate, status=%d", status);
+                    return status;
+                }
+                mVsyncState = VsyncState::Unregistered;
+                break;
+        }
     }
 
     return 1; // keep the callback
diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp
new file mode 100644
index 0000000..f400774
--- /dev/null
+++ b/libs/gui/FrameTimelineInfo.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FrameTimelineInfo"
+
+#include <inttypes.h>
+
+#include <android/os/IInputConstants.h>
+#include <gui/FrameTimelineInfo.h>
+#include <gui/LayerState.h>
+#include <utils/Errors.h>
+
+#include <cmath>
+
+using android::os::IInputConstants;
+
+namespace android {
+
+status_t FrameTimelineInfo::write(Parcel& output) const {
+    SAFE_PARCEL(output.writeInt64, vsyncId);
+    SAFE_PARCEL(output.writeInt32, inputEventId);
+    return NO_ERROR;
+}
+
+status_t FrameTimelineInfo::read(const Parcel& input) {
+    SAFE_PARCEL(input.readInt64, &vsyncId);
+    SAFE_PARCEL(input.readInt32, &inputEventId);
+    return NO_ERROR;
+}
+
+void FrameTimelineInfo::merge(const FrameTimelineInfo& other) {
+    // When merging vsync Ids we take the oldest valid one
+    if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) {
+        if (other.vsyncId > vsyncId) {
+            vsyncId = other.vsyncId;
+            inputEventId = other.inputEventId;
+        }
+    } else if (vsyncId == INVALID_VSYNC_ID) {
+        vsyncId = other.vsyncId;
+        inputEventId = other.inputEventId;
+    }
+}
+
+void FrameTimelineInfo::clear() {
+    vsyncId = INVALID_VSYNC_ID;
+    inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID;
+}
+
+}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a8d6832..f68f3e1 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -68,16 +68,19 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual status_t setTransactionState(
-            int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
-            const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
-            const InputWindowCommands& commands, int64_t desiredPresentTime, bool isAutoTimestamp,
-            const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
-            const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
+    status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+                                 const Vector<ComposerState>& state,
+                                 const Vector<DisplayState>& displays, uint32_t flags,
+                                 const sp<IBinder>& applyToken, const InputWindowCommands& commands,
+                                 int64_t desiredPresentTime, bool isAutoTimestamp,
+                                 const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+                                 const std::vector<ListenerCallbacks>& listenerCallbacks,
+                                 uint64_t transactionId) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
-        SAFE_PARCEL(data.writeInt64, frameTimelineVsyncId);
+        SAFE_PARCEL(frameTimelineInfo.write, data);
+
         SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size()));
         for (const auto& s : state) {
             SAFE_PARCEL(s.write, data);
@@ -108,15 +111,14 @@
         return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
-    virtual void bootFinished()
-    {
+    void bootFinished() override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
     }
 
-    virtual status_t captureDisplay(const DisplayCaptureArgs& args,
-                                    const sp<IScreenCaptureListener>& captureListener) {
+    status_t captureDisplay(const DisplayCaptureArgs& args,
+                            const sp<IScreenCaptureListener>& captureListener) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         SAFE_PARCEL(args.write, data);
@@ -125,8 +127,8 @@
         return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
     }
 
-    virtual status_t captureDisplay(uint64_t displayOrLayerStack,
-                                    const sp<IScreenCaptureListener>& captureListener) {
+    status_t captureDisplay(uint64_t displayOrLayerStack,
+                            const sp<IScreenCaptureListener>& captureListener) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         SAFE_PARCEL(data.writeUint64, displayOrLayerStack);
@@ -135,8 +137,8 @@
         return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
     }
 
-    virtual status_t captureLayers(const LayerCaptureArgs& args,
-                                   const sp<IScreenCaptureListener>& captureListener) {
+    status_t captureLayers(const LayerCaptureArgs& args,
+                           const sp<IScreenCaptureListener>& captureListener) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         SAFE_PARCEL(args.write, data);
@@ -145,9 +147,8 @@
         return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
     }
 
-    virtual bool authenticateSurfaceTexture(
-            const sp<IGraphicBufferProducer>& bufferProducer) const
-    {
+    bool authenticateSurfaceTexture(
+            const sp<IGraphicBufferProducer>& bufferProducer) const override {
         Parcel data, reply;
         int err = NO_ERROR;
         err = data.writeInterfaceToken(
@@ -180,8 +181,7 @@
         return result != 0;
     }
 
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const {
+    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override {
         if (!outSupported) {
             return UNEXPECTED_NULL;
         }
@@ -224,8 +224,8 @@
         return NO_ERROR;
     }
 
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection(
-            VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) {
+    sp<IDisplayEventConnection> createDisplayEventConnection(
+            VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override {
         Parcel data, reply;
         sp<IDisplayEventConnection> result;
         int err = data.writeInterfaceToken(
@@ -247,8 +247,7 @@
         return result;
     }
 
-    virtual sp<IBinder> createDisplay(const String8& displayName, bool secure)
-    {
+    sp<IBinder> createDisplay(const String8& displayName, bool secure) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         status_t status = data.writeString8(displayName);
@@ -272,15 +271,14 @@
         return display;
     }
 
-    virtual void destroyDisplay(const sp<IBinder>& display)
-    {
+    void destroyDisplay(const sp<IBinder>& display) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
         remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
     }
 
-    virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
+    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
@@ -297,7 +295,7 @@
         return {};
     }
 
-    virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeUint64(displayId.value);
@@ -305,8 +303,7 @@
         return reply.readStrongBinder();
     }
 
-    virtual void setPowerMode(const sp<IBinder>& display, int mode)
-    {
+    void setPowerMode(const sp<IBinder>& display, int mode) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -314,7 +311,7 @@
         remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
     }
 
-    virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) {
+    status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -326,7 +323,7 @@
         return result;
     }
 
-    virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
+    status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -336,7 +333,8 @@
         return reply.read(*info);
     }
 
-    virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>* configs) {
+    status_t getDisplayConfigs(const sp<IBinder>& display,
+                               Vector<DisplayConfig>* configs) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -354,9 +352,7 @@
         return result;
     }
 
-    virtual status_t getDisplayStats(const sp<IBinder>& display,
-            DisplayStatInfo* stats)
-    {
+    status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -370,8 +366,7 @@
         return result;
     }
 
-    virtual int getActiveConfig(const sp<IBinder>& display)
-    {
+    int getActiveConfig(const sp<IBinder>& display) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -379,8 +374,8 @@
         return reply.readInt32();
     }
 
-    virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<ColorMode>* outColorModes) {
+    status_t getDisplayColorModes(const sp<IBinder>& display,
+                                  Vector<ColorMode>* outColorModes) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -409,8 +404,8 @@
         return result;
     }
 
-    virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
-            ui::DisplayPrimaries& primaries) {
+    status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+                                       ui::DisplayPrimaries& primaries) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -435,7 +430,7 @@
         return result;
     }
 
-    virtual ColorMode getActiveColorMode(const sp<IBinder>& display) {
+    ColorMode getActiveColorMode(const sp<IBinder>& display) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -455,8 +450,7 @@
         return static_cast<ColorMode>(reply.readInt32());
     }
 
-    virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            ColorMode colorMode) {
+    status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -481,8 +475,8 @@
         return static_cast<status_t>(reply.readInt32());
     }
 
-    virtual status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display,
-                                                  bool* outSupport) const {
+    status_t getAutoLowLatencyModeSupport(const sp<IBinder>& display,
+                                          bool* outSupport) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         status_t result = data.writeStrongBinder(display);
@@ -499,7 +493,7 @@
         return reply.readBool(outSupport);
     }
 
-    virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+    void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -524,7 +518,8 @@
         }
     }
 
-    virtual status_t getGameContentTypeSupport(const sp<IBinder>& display, bool* outSupport) const {
+    status_t getGameContentTypeSupport(const sp<IBinder>& display,
+                                       bool* outSupport) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         status_t result = data.writeStrongBinder(display);
@@ -540,7 +535,7 @@
         return reply.readBool(outSupport);
     }
 
-    virtual void setGameContentType(const sp<IBinder>& display, bool on) {
+    void setGameContentType(const sp<IBinder>& display, bool on) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -563,7 +558,7 @@
         }
     }
 
-    virtual status_t clearAnimationFrameStats() {
+    status_t clearAnimationFrameStats() override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -578,7 +573,7 @@
         return reply.readInt32();
     }
 
-    virtual status_t getAnimationFrameStats(FrameStats* outStats) const {
+    status_t getAnimationFrameStats(FrameStats* outStats) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply);
@@ -586,8 +581,8 @@
         return reply.readInt32();
     }
 
-    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
-            HdrCapabilities* outCapabilities) const {
+    status_t getHdrCapabilities(const sp<IBinder>& display,
+                                HdrCapabilities* outCapabilities) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         status_t result = data.writeStrongBinder(display);
@@ -608,7 +603,7 @@
         return result;
     }
 
-    virtual status_t enableVSyncInjections(bool enable) {
+    status_t enableVSyncInjections(bool enable) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -629,7 +624,7 @@
         return result;
     }
 
-    virtual status_t injectVSync(nsecs_t when) {
+    status_t injectVSync(nsecs_t when) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -650,7 +645,7 @@
         return result;
     }
 
-    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
+    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override {
         if (!outLayers) {
             return UNEXPECTED_NULL;
         }
@@ -680,10 +675,10 @@
         return reply.readParcelableVector(outLayers);
     }
 
-    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
-                                              ui::PixelFormat* defaultPixelFormat,
-                                              ui::Dataspace* wideColorGamutDataspace,
-                                              ui::PixelFormat* wideColorGamutPixelFormat) const {
+    status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                      ui::PixelFormat* defaultPixelFormat,
+                                      ui::Dataspace* wideColorGamutDataspace,
+                                      ui::PixelFormat* wideColorGamutPixelFormat) const override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -703,7 +698,7 @@
         return error;
     }
 
-    virtual status_t getColorManagement(bool* outGetColorManagement) const {
+    status_t getColorManagement(bool* outGetColorManagement) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply);
@@ -715,10 +710,10 @@
         return err;
     }
 
-    virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
-                                                           ui::PixelFormat* outFormat,
-                                                           ui::Dataspace* outDataspace,
-                                                           uint8_t* outComponentMask) const {
+    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+                                                   ui::PixelFormat* outFormat,
+                                                   ui::Dataspace* outDataspace,
+                                                   uint8_t* outComponentMask) const override {
         if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE;
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -752,8 +747,8 @@
         return error;
     }
 
-    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
-                                                      uint8_t componentMask, uint64_t maxFrames) {
+    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                              uint8_t componentMask, uint64_t maxFrames) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -766,9 +761,9 @@
         return result;
     }
 
-    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
-                                               uint64_t timestamp,
-                                               DisplayedFrameStats* outStats) const {
+    status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                       uint64_t timestamp,
+                                       DisplayedFrameStats* outStats) const override {
         if (!outStats) return BAD_VALUE;
 
         Parcel data, reply;
@@ -805,7 +800,7 @@
         return result;
     }
 
-    virtual status_t getProtectedContentSupport(bool* outSupported) const {
+    status_t getProtectedContentSupport(bool* outSupported) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         status_t error =
@@ -817,8 +812,8 @@
         return error;
     }
 
-    virtual status_t isWideColorDisplay(const sp<IBinder>& token,
-                                        bool* outIsWideColorDisplay) const {
+    status_t isWideColorDisplay(const sp<IBinder>& token,
+                                bool* outIsWideColorDisplay) const override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -837,9 +832,8 @@
         return error;
     }
 
-    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
-                                               const sp<IBinder>& stopLayerHandle,
-                                               const sp<IRegionSamplingListener>& listener) {
+    status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+                                       const sp<IRegionSamplingListener>& listener) override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -868,7 +862,7 @@
         return error;
     }
 
-    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+    status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -888,12 +882,11 @@
         return error;
     }
 
-    virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t defaultConfig, bool allowGroupSwitching,
-                                                  float primaryRefreshRateMin,
-                                                  float primaryRefreshRateMax,
-                                                  float appRequestRefreshRateMin,
-                                                  float appRequestRefreshRateMax) {
+    status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t defaultConfig,
+                                          bool allowGroupSwitching, float primaryRefreshRateMin,
+                                          float primaryRefreshRateMax,
+                                          float appRequestRefreshRateMin,
+                                          float appRequestRefreshRateMax) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -947,13 +940,12 @@
         return reply.readInt32();
     }
 
-    virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t* outDefaultConfig,
-                                                  bool* outAllowGroupSwitching,
-                                                  float* outPrimaryRefreshRateMin,
-                                                  float* outPrimaryRefreshRateMax,
-                                                  float* outAppRequestRefreshRateMin,
-                                                  float* outAppRequestRefreshRateMax) {
+    status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
+                                          int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+                                          float* outPrimaryRefreshRateMin,
+                                          float* outPrimaryRefreshRateMax,
+                                          float* outAppRequestRefreshRateMin,
+                                          float* outAppRequestRefreshRateMax) override {
         if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
             !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
             !outAppRequestRefreshRateMax) {
@@ -1011,8 +1003,8 @@
         return reply.readInt32();
     }
 
-    virtual status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
-                                                 bool* outSupport) const {
+    status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+                                         bool* outSupport) const override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -1039,7 +1031,7 @@
         return NO_ERROR;
     }
 
-    virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) {
+    status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -1064,7 +1056,7 @@
         return NO_ERROR;
     }
 
-    virtual status_t notifyPowerBoost(int32_t boostId) {
+    status_t notifyPowerBoost(int32_t boostId) override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -1085,8 +1077,8 @@
         return NO_ERROR;
     }
 
-    virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
-                                             float lightPosY, float lightPosZ, float lightRadius) {
+    status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
+                                     float lightPosY, float lightPosZ, float lightRadius) override {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -1114,8 +1106,8 @@
         return NO_ERROR;
     }
 
-    virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
-                                  int8_t compatibility, bool shouldBeSeamless) {
+    status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+                          int8_t compatibility, bool shouldBeSeamless) override {
         Parcel data, reply;
         status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (err != NO_ERROR) {
@@ -1156,7 +1148,7 @@
         return reply.readInt32();
     }
 
-    virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) {
+    status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override {
         if (!outToken) return BAD_VALUE;
 
         Parcel data, reply;
@@ -1191,40 +1183,34 @@
         return NO_ERROR;
     }
 
-    virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
-                                           int64_t frameTimelineVsyncId) {
+    status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
+                                  const FrameTimelineInfo& frameTimelineInfo) override {
         Parcel data, reply;
         status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (err != NO_ERROR) {
-            ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err),
-                  -err);
+            ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err);
             return err;
         }
 
         err = data.writeStrongBinder(IInterface::asBinder(surface));
         if (err != NO_ERROR) {
-            ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err),
-                  -err);
+            ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err);
             return err;
         }
 
-        err = data.writeInt64(frameTimelineVsyncId);
-        if (err != NO_ERROR) {
-            ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err);
-            return err;
-        }
+        SAFE_PARCEL(frameTimelineInfo.write, data);
 
-        err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply);
+        err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply);
         if (err != NO_ERROR) {
-            ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err);
+            ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err);
             return err;
         }
 
         return reply.readInt32();
     }
 
-    virtual status_t addTransactionTraceListener(
-            const sp<gui::ITransactionTraceListener>& listener) {
+    status_t addTransactionTraceListener(
+            const sp<gui::ITransactionTraceListener>& listener) override {
         Parcel data, reply;
         SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
         SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
@@ -1235,7 +1221,7 @@
     /**
      * Get priority of the RenderEngine in surface flinger.
      */
-    virtual int getGPUContextPriority() {
+    int getGPUContextPriority() override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         status_t err =
@@ -1269,8 +1255,9 @@
         case SET_TRANSACTION_STATE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
-            int64_t frameTimelineVsyncId;
-            SAFE_PARCEL(data.readInt64, &frameTimelineVsyncId);
+            FrameTimelineInfo frameTimelineInfo;
+            SAFE_PARCEL(frameTimelineInfo.read, data);
+
             uint32_t count = 0;
             SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
             Vector<ComposerState> state;
@@ -1324,10 +1311,10 @@
             uint64_t transactionId = -1;
             SAFE_PARCEL(data.readUint64, &transactionId);
 
-            return setTransactionState(frameTimelineVsyncId, state, displays, stateFlags,
-                                       applyToken, inputWindowCommands, desiredPresentTime,
-                                       isAutoTimestamp, uncachedBuffer, hasListenerCallbacks,
-                                       listenerCallbacks, transactionId);
+            return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken,
+                                       inputWindowCommands, desiredPresentTime, isAutoTimestamp,
+                                       uncachedBuffer, hasListenerCallbacks, listenerCallbacks,
+                                       transactionId);
         }
         case BOOT_FINISHED: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -2078,30 +2065,26 @@
             }
             return NO_ERROR;
         }
-        case SET_FRAME_TIMELINE_VSYNC: {
+        case SET_FRAME_TIMELINE_INFO: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> binder;
             status_t err = data.readStrongBinder(&binder);
             if (err != NO_ERROR) {
-                ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)",
-                      strerror(-err), -err);
+                ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err),
+                      -err);
                 return err;
             }
             sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
             if (!surface) {
-                ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)",
+                ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)",
                       strerror(-err), -err);
                 return err;
             }
-            int64_t frameTimelineVsyncId;
-            err = data.readInt64(&frameTimelineVsyncId);
-            if (err != NO_ERROR) {
-                ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err),
-                      -err);
-                return err;
-            }
 
-            status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId);
+            FrameTimelineInfo frameTimelineInfo;
+            SAFE_PARCEL(frameTimelineInfo.read, data);
+
+            status_t result = setFrameTimelineInfo(surface, frameTimelineInfo);
             reply->writeInt32(result);
             return NO_ERROR;
         }
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 1808571..0ded936 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -92,10 +92,8 @@
     return err;
 }
 
-JankData::JankData() :
-        frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
-        jankType(JankType::None) {
-}
+JankData::JankData()
+      : frameVsyncId(FrameTimelineInfo::INVALID_VSYNC_ID), jankType(JankType::None) {}
 
 status_t JankData::writeToParcel(Parcel* output) const {
     SAFE_PARCEL(output->writeInt64, frameVsyncId);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 2946aae..fff3305 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -63,7 +63,7 @@
         shouldBeSeamless(true),
         fixedTransformHint(ui::Transform::ROT_INVALID),
         frameNumber(0),
-        frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+        frameTimelineInfo(),
         autoRefresh(false) {
     matrix.dsdx = matrix.dtdy = 1.0f;
     matrix.dsdy = matrix.dtdx = 0.0f;
@@ -151,7 +151,7 @@
     SAFE_PARCEL(output.writeBool, shouldBeSeamless);
     SAFE_PARCEL(output.writeUint32, fixedTransformHint);
     SAFE_PARCEL(output.writeUint64, frameNumber);
-    SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+    SAFE_PARCEL(frameTimelineInfo.write, output);
     SAFE_PARCEL(output.writeBool, autoRefresh);
 
     SAFE_PARCEL(output.writeUint32, blurRegions.size());
@@ -270,7 +270,7 @@
     SAFE_PARCEL(input.readUint32, &tmpUint32);
     fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
     SAFE_PARCEL(input.readUint64, &frameNumber);
-    SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+    SAFE_PARCEL(frameTimelineInfo.read, input);
     SAFE_PARCEL(input.readBool, &autoRefresh);
 
     uint32_t numRegions = 0;
@@ -426,9 +426,6 @@
         what |= eReparentChildren;
         reparentSurfaceControl = other.reparentSurfaceControl;
     }
-    if (other.what & eDetachChildren) {
-        what |= eDetachChildren;
-    }
     if (other.what & eRelativeLayerChanged) {
         what |= eRelativeLayerChanged;
         what &= ~eLayerChanged;
@@ -537,15 +534,9 @@
         what |= eFrameNumberChanged;
         frameNumber = other.frameNumber;
     }
-    if (other.what & eFrameTimelineVsyncChanged) {
-        // When merging vsync Ids we take the oldest valid one
-        if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
-            other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
-            frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId);
-        } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) {
-            frameTimelineVsyncId = other.frameTimelineVsyncId;
-        }
-        what |= eFrameTimelineVsyncChanged;
+    if (other.what & eFrameTimelineInfoChanged) {
+        what |= eFrameTimelineInfoChanged;
+        frameTimelineInfo.merge(other.frameTimelineInfo);
     }
     if (other.what & eAutoRefreshChanged) {
         what |= eAutoRefreshChanged;
@@ -644,11 +635,13 @@
 status_t CaptureArgs::write(Parcel& output) const {
     SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(pixelFormat));
     SAFE_PARCEL(output.write, sourceCrop);
-    SAFE_PARCEL(output.writeFloat, frameScale);
+    SAFE_PARCEL(output.writeFloat, frameScaleX);
+    SAFE_PARCEL(output.writeFloat, frameScaleY);
     SAFE_PARCEL(output.writeBool, captureSecureLayers);
     SAFE_PARCEL(output.writeInt32, uid);
     SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
     SAFE_PARCEL(output.writeBool, allowProtected);
+    SAFE_PARCEL(output.writeBool, grayscale);
     return NO_ERROR;
 }
 
@@ -657,12 +650,14 @@
     SAFE_PARCEL(input.readInt32, &value);
     pixelFormat = static_cast<ui::PixelFormat>(value);
     SAFE_PARCEL(input.read, sourceCrop);
-    SAFE_PARCEL(input.readFloat, &frameScale);
+    SAFE_PARCEL(input.readFloat, &frameScaleX);
+    SAFE_PARCEL(input.readFloat, &frameScaleY);
     SAFE_PARCEL(input.readBool, &captureSecureLayers);
     SAFE_PARCEL(input.readInt32, &uid);
     SAFE_PARCEL(input.readInt32, &value);
     dataspace = static_cast<ui::Dataspace>(value);
     SAFE_PARCEL(input.readBool, &allowProtected);
+    SAFE_PARCEL(input.readBool, &grayscale);
     return NO_ERROR;
 }
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e82f0cc..59ad8d2 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1496,8 +1496,8 @@
     case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER:
         res = dispatchGetLastQueuedBuffer(args);
         break;
-    case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC:
-        res = dispatchSetFrameTimelineVsync(args);
+    case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO:
+        res = dispatchSetFrameTimelineInfo(args);
         break;
     default:
         res = NAME_NOT_FOUND;
@@ -1806,12 +1806,13 @@
     return result;
 }
 
-int Surface::dispatchSetFrameTimelineVsync(va_list args) {
+int Surface::dispatchSetFrameTimelineInfo(va_list args) {
     ATRACE_CALL();
     auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
+    auto inputEventId = static_cast<int32_t>(va_arg(args, int32_t));
 
-    ALOGV("Surface::dispatchSetFrameTimelineVsync");
-    return setFrameTimelineVsync(frameTimelineVsyncId);
+    ALOGV("Surface::%s", __func__);
+    return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId});
 }
 
 bool Surface::transformToDisplayInverse() {
@@ -2579,9 +2580,8 @@
                                            shouldBeSeamless);
 }
 
-status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
-    return composerService()->setFrameTimelineVsync(mGraphicBufferProducer,
-        frameTimelineVsyncId);
+status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) {
+    return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
 }
 
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 96c099b..550803d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -396,7 +396,7 @@
         mContainsBuffer(other.mContainsBuffer),
         mDesiredPresentTime(other.mDesiredPresentTime),
         mIsAutoTimestamp(other.mIsAutoTimestamp),
-        mFrameTimelineVsyncId(other.mFrameTimelineVsyncId),
+        mFrameTimelineInfo(other.mFrameTimelineInfo),
         mApplyToken(other.mApplyToken) {
     mDisplayStates = other.mDisplayStates;
     mComposerStates = other.mComposerStates;
@@ -427,7 +427,9 @@
     const bool containsBuffer = parcel->readBool();
     const int64_t desiredPresentTime = parcel->readInt64();
     const bool isAutoTimestamp = parcel->readBool();
-    const int64_t frameTimelineVsyncId = parcel->readInt64();
+    FrameTimelineInfo frameTimelineInfo;
+    SAFE_PARCEL(frameTimelineInfo.read, *parcel);
+
     sp<IBinder> applyToken;
     parcel->readNullableStrongBinder(&applyToken);
     size_t count = static_cast<size_t>(parcel->readUint32());
@@ -502,7 +504,7 @@
     mContainsBuffer = containsBuffer;
     mDesiredPresentTime = desiredPresentTime;
     mIsAutoTimestamp = isAutoTimestamp;
-    mFrameTimelineVsyncId = frameTimelineVsyncId;
+    mFrameTimelineInfo = frameTimelineInfo;
     mDisplayStates = displayStates;
     mListenerCallbacks = listenerCallbacks;
     mComposerStates = composerStates;
@@ -534,7 +536,7 @@
     parcel->writeBool(mContainsBuffer);
     parcel->writeInt64(mDesiredPresentTime);
     parcel->writeBool(mIsAutoTimestamp);
-    parcel->writeInt64(mFrameTimelineVsyncId);
+    SAFE_PARCEL(mFrameTimelineInfo.write, *parcel);
     parcel->writeStrongBinder(mApplyToken);
     parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
     for (auto const& displayState : mDisplayStates) {
@@ -613,13 +615,7 @@
     mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
     mApplyToken = other.mApplyToken;
 
-    // When merging vsync Ids we take the oldest one
-    if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
-        other.mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
-        mFrameTimelineVsyncId = std::max(mFrameTimelineVsyncId, other.mFrameTimelineVsyncId);
-    } else if (mFrameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) {
-        mFrameTimelineVsyncId = other.mFrameTimelineVsyncId;
-    }
+    mFrameTimelineInfo.merge(other.mFrameTimelineInfo);
 
     other.clear();
     return *this;
@@ -639,7 +635,7 @@
     mExplicitEarlyWakeupEnd = false;
     mDesiredPresentTime = 0;
     mIsAutoTimestamp = true;
-    mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+    mFrameTimelineInfo.clear();
     mApplyToken = nullptr;
 }
 
@@ -651,9 +647,8 @@
     uncacheBuffer.id = cacheId;
 
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
-    sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {},
-                            systemTime(), true, uncacheBuffer, false, {},
-                            0 /* Undefined transactionId */);
+    sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true,
+                            uncacheBuffer, false, {}, 0 /* Undefined transactionId */);
 }
 
 void SurfaceComposerClient::Transaction::cacheBuffers() {
@@ -773,7 +768,7 @@
             ? mApplyToken
             : IInterface::asBinder(TransactionCompletedListener::getIInstance());
 
-    sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
+    sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
                             mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                             {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
                             hasListenerCallbacks, listenerCallbacks, mId);
@@ -1391,19 +1386,6 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
-        const sp<SurfaceControl>& sc) {
-    layer_state_t* s = getLayerState(sc);
-    if (!s) {
-        mStatus = BAD_INDEX;
-        return *this;
-    }
-    s->what |= layer_state_t::eDetachChildren;
-
-    registerSurfaceControlForCallback(sc);
-    return *this;
-}
-
 #ifndef NO_INPUT
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
         const sp<SurfaceControl>& sc,
@@ -1549,22 +1531,22 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync(
-        int64_t frameTimelineVsyncId) {
-    mFrameTimelineVsyncId = frameTimelineVsyncId;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo(
+        const FrameTimelineInfo& frameTimelineInfo) {
+    mFrameTimelineInfo = frameTimelineInfo;
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync(
-        const sp<SurfaceControl>& sc, int64_t frameTimelineVsyncId) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo(
+        const sp<SurfaceControl>& sc, const FrameTimelineInfo& frameTimelineInfo) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
 
-    s->what |= layer_state_t::eFrameTimelineVsyncChanged;
-    s->frameTimelineVsyncId = frameTimelineVsyncId;
+    s->what |= layer_state_t::eFrameTimelineInfoChanged;
+    s->frameTimelineInfo = frameTimelineInfo;
     return *this;
 }
 
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 7f69bc4..fa3efe1 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -92,7 +92,7 @@
     void flushShadowQueue() { mFlushShadowQueue = true; }
 
     status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
-    status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+    status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
 
     virtual ~BLASTBufferQueue();
 
@@ -156,7 +156,7 @@
     // This is only relevant for shared buffer mode.
     bool mAutoRefresh GUARDED_BY(mMutex) = false;
 
-    std::queue<int64_t> mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex);
+    std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex);
 
     // Last acquired buffer's scaling mode. This is used to check if we should update the blast
     // layer size immediately or wait until we get the next buffer. This will support scenarios
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 5587acf..4175a49 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -25,7 +25,7 @@
     // The Vsync Id corresponsing to this vsync event. This will be used to
     // populate ISurfaceComposer::setFrameTimelineVsync and
     // SurfaceComposerClient::setFrameTimelineVsync
-    int64_t id = ISurfaceComposer::INVALID_VSYNC_ID;
+    int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
 
     // The deadline in CLOCK_MONOTONIC that the app needs to complete its
     // frame by (both on the CPU and the GPU)
@@ -52,7 +52,20 @@
 private:
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
-    bool mWaitingForVsync;
+    // The state of vsync event registration and whether the client is expecting
+    // an event or not.
+    enum class VsyncState {
+        // The dispatcher is not registered for vsync events.
+        Unregistered,
+        // The dispatcher is registered to receive vsync events but should not dispatch it to the
+        // client as the client is not expecting a vsync event.
+        Registered,
+
+        // The dispatcher is registered to receive vsync events and supposed to dispatch it to
+        // the client.
+        RegisteredAndWaitingForVsync,
+    };
+    VsyncState mVsyncState;
 
     std::vector<FrameRateOverride> mFrameRateOverrides;
 
diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h
new file mode 100644
index 0000000..3b4c009
--- /dev/null
+++ b/libs/gui/include/gui/FrameTimelineInfo.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 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 <stdint.h>
+
+#include <android/os/IInputConstants.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+struct FrameTimelineInfo {
+    // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java
+    static constexpr int64_t INVALID_VSYNC_ID = -1;
+
+    // The vsync id that was used to start the transaction
+    int64_t vsyncId = INVALID_VSYNC_ID;
+
+    // The id of the input event that caused this buffer
+    int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
+
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
+
+    void merge(const FrameTimelineInfo& other);
+    void clear();
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 86f3c60..81ff6b0 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -24,6 +24,7 @@
 
 #include <android/gui/IScreenCaptureListener.h>
 #include <android/gui/ITransactionTraceListener.h>
+#include <gui/FrameTimelineInfo.h>
 #include <gui/ITransactionCompletedListener.h>
 
 #include <input/Flags.h>
@@ -117,9 +118,6 @@
 
     using EventRegistrationFlags = Flags<EventRegistration>;
 
-    // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java
-    static constexpr int64_t INVALID_VSYNC_ID = -1;
-
     /*
      * Create a connection with SurfaceFlinger.
      */
@@ -164,7 +162,7 @@
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual status_t setTransactionState(
-            int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
+            const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
             const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
             const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
             bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
@@ -494,11 +492,11 @@
     virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0;
 
     /*
-     * Sets the frame timeline vsync id received from choreographer that corresponds to next
+     * Sets the frame timeline vsync info received from choreographer that corresponds to next
      * buffer submitted on that surface.
      */
-    virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
-                                           int64_t frameTimelineVsyncId) = 0;
+    virtual status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
+                                          const FrameTimelineInfo& frameTimelineInfo) = 0;
 
     /*
      * Adds a TransactionTraceListener to listen for transaction tracing state updates.
@@ -569,7 +567,7 @@
         SET_GAME_CONTENT_TYPE,
         SET_FRAME_RATE,
         ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
-        SET_FRAME_TIMELINE_VSYNC,
+        SET_FRAME_TIMELINE_INFO,
         ADD_TRANSACTION_TRACE_LISTENER,
         GET_GPU_CONTEXT_PRIORITY,
         // Always append new enum to the end.
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index b1305c6..2f9a0c0 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -102,7 +102,7 @@
         /* was ScalingModeChanged, now available 0x00000400, */
         eShadowRadiusChanged = 0x00000800,
         eReparentChildren = 0x00001000,
-        eDetachChildren = 0x00002000,
+        /* was eDetachChildren, now available 0x00002000, */
         eRelativeLayerChanged = 0x00004000,
         eReparent = 0x00008000,
         eColorChanged = 0x00010000,
@@ -132,7 +132,7 @@
         eProducerDisconnect = 0x100'00000000,
         eFixedTransformHintChanged = 0x200'00000000,
         eFrameNumberChanged = 0x400'00000000,
-        eFrameTimelineVsyncChanged = 0x800'00000000,
+        eFrameTimelineInfoChanged = 0x800'00000000,
         eBlurRegionsChanged = 0x1000'00000000,
         eAutoRefreshChanged = 0x2000'00000000,
     };
@@ -238,7 +238,7 @@
     // graphics producer.
     uint64_t frameNumber;
 
-    int64_t frameTimelineVsyncId;
+    FrameTimelineInfo frameTimelineInfo;
 
     // Indicates that the consumer should acquire the next frame as soon as it
     // can and not wait for a frame to become available. This is only relevant
@@ -328,7 +328,8 @@
 
     ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
     Rect sourceCrop;
-    float frameScale{1};
+    float frameScaleX{1};
+    float frameScaleY{1};
     bool captureSecureLayers{false};
     int32_t uid{UNSET_UID};
     // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
@@ -346,6 +347,8 @@
     // the contents being accessed/captured by screenshot or unsecure display.
     bool allowProtected = false;
 
+    bool grayscale = false;
+
     virtual status_t write(Parcel& output) const;
     virtual status_t read(const Parcel& input);
 };
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 43b5dcd..b6b5c7c 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -18,6 +18,7 @@
 #define ANDROID_GUI_SURFACE_H
 
 #include <gui/BufferQueueDefs.h>
+#include <gui/FrameTimelineInfo.h>
 #include <gui/HdrMetadata.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
@@ -187,7 +188,7 @@
     status_t getConsumerUsage(uint64_t* outUsage) const;
 
     virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
-    virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+    virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
 
 protected:
     virtual ~Surface();
@@ -273,7 +274,7 @@
     int dispatchAddQueueInterceptor(va_list args);
     int dispatchAddQueryInterceptor(va_list args);
     int dispatchGetLastQueuedBuffer(va_list args);
-    int dispatchSetFrameTimelineVsync(va_list args);
+    int dispatchSetFrameTimelineInfo(va_list args);
     bool transformToDisplayInverse();
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 11db658..e7abfe6 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -385,8 +385,8 @@
         int64_t mDesiredPresentTime = 0;
         bool mIsAutoTimestamp = true;
 
-        // The vsync Id provided by Choreographer.getVsyncId
-        int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+        // The vsync id provided by Choreographer.getVsyncId and the input event id
+        FrameTimelineInfo mFrameTimelineInfo;
 
         // If not null, transactions will be queued up using this token otherwise a common token
         // per process will be used.
@@ -508,18 +508,6 @@
         // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour.
         Transaction& setFrameNumber(const sp<SurfaceControl>& sc, uint64_t frameNumber);
 
-        // Detaches all child surfaces (and their children recursively)
-        // from their SurfaceControl.
-        // The child SurfaceControls will not throw exceptions or return errors,
-        // but transactions will have no effect.
-        // The child surfaces will continue to follow their parent surfaces,
-        // and remain eligible for rendering, but their relative state will be
-        // frozen. We use this in the WindowManager, in app shutdown/relaunch
-        // scenarios, where the app would otherwise clean up its child Surfaces.
-        // Sometimes the WindowManager needs to extend their lifetime slightly
-        // in order to perform an exit animation or prevent flicker.
-        Transaction& detachChildren(const sp<SurfaceControl>& sc);
-
 #ifndef NO_INPUT
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
         Transaction& setFocusedWindow(const FocusRequest& request);
@@ -546,11 +534,12 @@
         Transaction& setFixedTransformHint(const sp<SurfaceControl>& sc, int32_t transformHint);
 
         // Sets the frame timeline vsync id received from choreographer that corresponds
-        // to the transaction.
-        Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+        // to the transaction, and the input event id that identifies the input event that caused
+        // the current frame.
+        Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo);
         // Variant that only applies to a specific SurfaceControl.
-        Transaction& setFrameTimelineVsync(const sp<SurfaceControl>& sc,
-                int64_t frameTimelineVsyncId);
+        Transaction& setFrameTimelineInfo(const sp<SurfaceControl>& sc,
+                                          const FrameTimelineInfo& frameTimelineInfo);
 
         // Indicates that the consumer should acquire the next frame as soon as it
         // can and not wait for a frame to become available. This is only relevant
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 63db9a7..3f7a5b1 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -695,7 +695,7 @@
     void destroyDisplay(const sp<IBinder>& /*display */) override {}
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
-    status_t setTransactionState(int64_t /*frameTimelineVsyncId*/,
+    status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
                                  const Vector<ComposerState>& /*state*/,
                                  const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
                                  const sp<IBinder>& /*applyToken*/,
@@ -877,8 +877,8 @@
         return NO_ERROR;
     }
 
-    status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& /*surface*/,
-                                   int64_t /*frameTimelineVsyncId*/) override {
+    status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& /*surface*/,
+                                  const FrameTimelineInfo& /*frameTimelineInfo*/) override {
         return NO_ERROR;
     }
 
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 2ed441d..698cf6e 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -166,6 +166,7 @@
         mKeyboardType(other.mKeyboardType),
         mKeyCharacterMap(other.mKeyCharacterMap),
         mHasVibrator(other.mHasVibrator),
+        mHasBattery(other.mHasBattery),
         mHasButtonUnderPad(other.mHasButtonUnderPad),
         mHasSensor(other.mHasSensor),
         mMotionRanges(other.mMotionRanges),
@@ -187,6 +188,7 @@
     mSources = 0;
     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
     mHasVibrator = false;
+    mHasBattery = false;
     mHasButtonUnderPad = false;
     mHasSensor = false;
     mMotionRanges.clear();
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 6316b59..bce0ec8 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -28,4 +28,13 @@
       * to identify apps that are using this flag.
       */
     const long BLOCK_FLAG_SLIPPERY = 157929241;
+
+    // Indicate invalid battery capacity
+    const int INVALID_BATTERY_CAPACITY = -1;
+
+    /**
+     * Every input event has an id. This constant value is used when a valid input event id is not
+     * available.
+     */
+    const int INVALID_INPUT_EVENT_ID = 0;
 }
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 6d91916..6b085a3 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -21,7 +21,7 @@
 #include <gui/DisplayEventDispatcher.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
-#include <nativehelper/JNIHelp.h>
+#include <jni.h>
 #include <private/android/choreographer.h>
 #include <utils/Looper.h>
 #include <utils/Timers.h>
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index f56b3a2..6574ae6 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -53,15 +53,13 @@
         "libcutils",
         "libEGL",
         "libGLESv2",
-        "libnativehelper",
     ],
 
-    export_shared_lib_headers: [
-        "libnativehelper",
-    ],
+    export_header_lib_headers: ["jni_headers"],
 
     header_libs: [
+        "jni_headers",
         "libnativedisplay_headers",
+        "libnativehelper_header_only",
     ],
-
 }
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index d3a4a66..0f4fd45 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -18,7 +18,7 @@
 
 #include <apex/choreographer.h>
 #include <inttypes.h>
-#include <nativehelper/JNIHelp.h>
+#include <jni.h>
 
 namespace android {
 
diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index f371667..85fe42f 100644
--- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -19,7 +19,7 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <nativehelper/JNIHelp.h>
+#include <jni.h>
 #include <system/graphics.h>
 
 // This file provides a facade API on top of SurfaceTexture, which avoids using
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
index ebe4484..c214ab7 100644
--- a/libs/nativedisplay/surfacetexture/surface_texture.cpp
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -29,8 +29,7 @@
 #include <mutex>
 
 #include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/scoped_local_ref.h>
 
 struct ASurfaceTexture {
     android::sp<android::SurfaceTexture> consumer;
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 82d2e66..ffe4412 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -255,7 +255,7 @@
     NATIVE_WINDOW_ALLOCATE_BUFFERS                = 45,    /* private */
     NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER          = 46,    /* private */
     NATIVE_WINDOW_SET_QUERY_INTERCEPTOR           = 47,    /* private */
-    NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC        = 48,    /* private */
+    NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO         = 48,    /* private */
     // clang-format on
 };
 
@@ -1023,10 +1023,11 @@
                            (int)compatibility, (int)shouldBeSeamless);
 }
 
-static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window,
-                                                         int64_t frameTimelineVsyncId) {
-    return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC,
-                           frameTimelineVsyncId);
+static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window,
+                                                         int64_t frameTimelineVsyncId,
+                                                         int32_t inputEventId) {
+    return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO,
+                           frameTimelineVsyncId, inputEventId);
 }
 
 // ------------------------------------------------------------------------------------------------
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 7bddee6..4714469 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -64,13 +64,15 @@
     }
 }
 
-void SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
+status_t SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
         const sp<hardware::ISensorPrivacyListener>& listener)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
     if (service != nullptr) {
-        service->addIndividualSensorPrivacyListener(userId, sensor, listener);
+        return service->addIndividualSensorPrivacyListener(userId, sensor, listener)
+                .transactionError();
     }
+    return UNEXPECTED_NULL;
 }
 
 void SensorPrivacyManager::removeSensorPrivacyListener(
@@ -106,6 +108,19 @@
     return false;
 }
 
+status_t SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor,
+        bool &returnVal)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        binder::Status res = service->isIndividualSensorPrivacyEnabled(userId, sensor, &returnVal);
+        return res.transactionError();
+    }
+    // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+    returnVal = false;
+    return UNKNOWN_ERROR;
+}
+
 status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index bd7c726..12778e1 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -36,11 +36,12 @@
     SensorPrivacyManager();
 
     void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
-    void addIndividualSensorPrivacyListener(int userId, int sensor,
+    status_t addIndividualSensorPrivacyListener(int userId, int sensor,
             const sp<hardware::ISensorPrivacyListener>& listener);
     void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     bool isSensorPrivacyEnabled();
     bool isIndividualSensorPrivacyEnabled(int userId, int sensor);
+    status_t isIndividualSensorPrivacyEnabled(int userId, int sensor, bool &result);
 
     status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
     status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index ea9b483..69aea84 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -108,6 +108,10 @@
     virtual bool isVibrating(int32_t deviceId) = 0;
 
     virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
+    /* Get battery level of a particular input device. */
+    virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0;
+    /* Get battery status of a particular input device. */
+    virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0;
 
     /* Return true if the device can send input events to the specified display. */
     virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index abda4ef..7f979f2 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -30,6 +30,7 @@
         "mapper/accumulator/CursorScrollAccumulator.cpp",
         "mapper/accumulator/SingleTouchMotionAccumulator.cpp",
         "mapper/accumulator/TouchButtonAccumulator.cpp",
+        "mapper/BatteryInputMapper.cpp",
         "mapper/CursorInputMapper.cpp",
         "mapper/ExternalStylusInputMapper.cpp",
         "mapper/InputMapper.cpp",
@@ -60,7 +61,11 @@
         "libui",
         "libutils",
     ],
+    static_libs: [
+        "libc++fs",
+    ],
     header_libs: [
+        "libbatteryservice_headers",
         "libinputreader_headers",
     ],
 }
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index b97ff90..8f8c051 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -29,11 +29,14 @@
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
 #include <sys/limits.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <unistd.h>
 
 #define LOG_TAG "EventHub"
 
 // #define LOG_NDEBUG 0
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <input/KeyCharacterMap.h>
@@ -64,6 +67,23 @@
 static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
 static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
 
+// must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c
+static const std::unordered_map<std::string, int32_t> BATTERY_STATUS =
+        {{"Unknown", BATTERY_STATUS_UNKNOWN},
+         {"Charging", BATTERY_STATUS_CHARGING},
+         {"Discharging", BATTERY_STATUS_DISCHARGING},
+         {"Not charging", BATTERY_STATUS_NOT_CHARGING},
+         {"Full", BATTERY_STATUS_FULL}};
+
+// Mapping taken from
+// https://gitlab.freedesktop.org/upower/upower/-/blob/master/src/linux/up-device-supply.c#L484
+static const std::unordered_map<std::string, int32_t> BATTERY_LEVEL = {{"Critical", 5},
+                                                                       {"Low", 10},
+                                                                       {"Normal", 55},
+                                                                       {"High", 70},
+                                                                       {"Full", 100},
+                                                                       {"Unknown", 50}};
+
 static inline const char* toString(bool value) {
     return value ? "true" : "false";
 }
@@ -127,6 +147,73 @@
     return inputEventTime;
 }
 
+/**
+ * Returns the sysfs root path of the input device
+ *
+ */
+static std::filesystem::path getSysfsRootPath(const char* devicePath) {
+    std::error_code errorCode;
+
+    // Stat the device path to get the major and minor number of the character file
+    struct stat statbuf;
+    if (stat(devicePath, &statbuf) == -1) {
+        ALOGE("Could not stat device %s due to error: %s.", devicePath, std::strerror(errno));
+        return std::filesystem::path();
+    }
+
+    unsigned int major_num = major(statbuf.st_rdev);
+    unsigned int minor_num = minor(statbuf.st_rdev);
+
+    // Realpath "/sys/dev/char/{major}:{minor}" to get the sysfs path to the input event
+    auto sysfsPath = std::filesystem::path("/sys/dev/char/");
+    sysfsPath /= std::to_string(major_num) + ":" + std::to_string(minor_num);
+    sysfsPath = std::filesystem::canonical(sysfsPath, errorCode);
+
+    // Make sure nothing went wrong in call to canonical()
+    if (errorCode) {
+        ALOGW("Could not run filesystem::canonical() due to error %d : %s.", errorCode.value(),
+              errorCode.message().c_str());
+        return std::filesystem::path();
+    }
+
+    // Continue to go up a directory until we reach a directory named "input"
+    while (sysfsPath != "/" && sysfsPath.filename() != "input") {
+        sysfsPath = sysfsPath.parent_path();
+    }
+
+    // Then go up one more and you will be at the sysfs root of the device
+    sysfsPath = sysfsPath.parent_path();
+
+    // Make sure we didn't reach root path and that directory actually exists
+    if (sysfsPath == "/" || !std::filesystem::exists(sysfsPath, errorCode)) {
+        if (errorCode) {
+            ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+                  errorCode.message().c_str());
+        }
+
+        // Not found
+        return std::filesystem::path();
+    }
+
+    return sysfsPath;
+}
+
+/**
+ * Returns the power supply node in sys fs
+ *
+ */
+static std::filesystem::path findPowerSupplyNode(const std::filesystem::path& sysfsRootPath) {
+    for (auto path = sysfsRootPath; path != "/"; path = path.parent_path()) {
+        std::error_code errorCode;
+        auto iter = std::filesystem::directory_iterator(path / "power_supply", errorCode);
+        if (!errorCode && iter != std::filesystem::directory_iterator()) {
+            return iter->path();
+        }
+    }
+    // Not found
+    return std::filesystem::path();
+}
+
 // --- Global Functions ---
 
 Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses) {
@@ -976,6 +1063,56 @@
     return nullptr;
 }
 
+std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const {
+    std::scoped_lock _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    std::string buffer;
+
+    if (!device || (device->sysfsBatteryPath.empty())) {
+        return std::nullopt;
+    }
+
+    // Some devices report battery capacity as an integer through the "capacity" file
+    if (base::ReadFileToString(device->sysfsBatteryPath / "capacity", &buffer)) {
+        return std::stoi(buffer);
+    }
+
+    // Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX
+    // These values are taken from kernel source code include/linux/power_supply.h
+    if (base::ReadFileToString(device->sysfsBatteryPath / "capacity_level", &buffer)) {
+        const auto it = BATTERY_LEVEL.find(buffer);
+        if (it != BATTERY_LEVEL.end()) {
+            return it->second;
+        }
+    }
+    return std::nullopt;
+}
+
+std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const {
+    std::scoped_lock _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    std::string buffer;
+
+    if (!device || (device->sysfsBatteryPath.empty())) {
+        return std::nullopt;
+    }
+
+    if (!base::ReadFileToString(device->sysfsBatteryPath / "status", &buffer)) {
+        ALOGE("Failed to read sysfs battery info: %s", strerror(errno));
+        return std::nullopt;
+    }
+
+    // Remove trailing new line
+    buffer.erase(std::remove(buffer.begin(), buffer.end(), '\n'), buffer.end());
+    const auto it = BATTERY_STATUS.find(buffer);
+
+    if (it != BATTERY_STATUS.end()) {
+        return it->second;
+    }
+
+    return std::nullopt;
+}
+
 size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
     ALOG_ASSERT(bufferSize >= 1);
 
@@ -1584,6 +1721,18 @@
         return -1;
     }
 
+    // Grab the device's sysfs path
+    device->sysfsRootPath = getSysfsRootPath(devicePath.c_str());
+
+    if (!device->sysfsRootPath.empty()) {
+        device->sysfsBatteryPath = findPowerSupplyNode(device->sysfsRootPath);
+
+        // Check if a battery exists
+        if (!device->sysfsBatteryPath.empty()) {
+            device->classes |= InputDeviceClass::BATTERY;
+        }
+    }
+
     // Determine whether the device has a mic.
     if (device->deviceHasMicLocked()) {
         device->classes |= InputDeviceClass::MIC;
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 3e6910d..8fc6f4a 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -21,6 +21,7 @@
 #include <input/Flags.h>
 #include <algorithm>
 
+#include "BatteryInputMapper.h"
 #include "CursorInputMapper.h"
 #include "ExternalStylusInputMapper.h"
 #include "InputReaderContext.h"
@@ -160,6 +161,11 @@
         mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
     }
 
+    // Battery-like devices.
+    if (classes.test(InputDeviceClass::BATTERY)) {
+        mappers.push_back(std::make_unique<BatteryInputMapper>(*contextPtr));
+    }
+
     // Keyboard-like devices.
     uint32_t keyboardSource = 0;
     int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
@@ -490,6 +496,15 @@
     for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); });
 }
 
+std::optional<int32_t> InputDevice::getBatteryCapacity() {
+    return first_in_mappers<int32_t>(
+            [](InputMapper& mapper) { return mapper.getBatteryCapacity(); });
+}
+
+std::optional<int32_t> InputDevice::getBatteryStatus() {
+    return first_in_mappers<int32_t>([](InputMapper& mapper) { return mapper.getBatteryStatus(); });
+}
+
 int32_t InputDevice::getMetaState() {
     int32_t result = 0;
     for_each_mapper([&result](InputMapper& mapper) { result |= mapper.getMetaState(); });
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 7c448e4..de5d0e6 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -673,6 +673,26 @@
     }
 }
 
+std::optional<int32_t> InputReader::getBatteryCapacity(int32_t deviceId) {
+    std::scoped_lock _l(mLock);
+
+    InputDevice* device = findInputDeviceLocked(deviceId);
+    if (device) {
+        return device->getBatteryCapacity();
+    }
+    return std::nullopt;
+}
+
+std::optional<int32_t> InputReader::getBatteryStatus(int32_t deviceId) {
+    std::scoped_lock _l(mLock);
+
+    InputDevice* device = findInputDeviceLocked(deviceId);
+    if (device) {
+        return device->getBatteryStatus();
+    }
+    return std::nullopt;
+}
+
 bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
     std::scoped_lock _l(mLock);
 
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 2cea017..30967df 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -23,6 +23,9 @@
 #include <vector>
 
 #include <input/Flags.h>
+#include <filesystem>
+
+#include <batteryservice/BatteryService.h>
 #include <input/Input.h>
 #include <input/InputDevice.h>
 #include <input/KeyCharacterMap.h>
@@ -121,6 +124,9 @@
     /* The input device has a sensor like accelerometer, gyro, etc */
     SENSOR = 0x00002000,
 
+    /* The input device has a battery */
+    BATTERY = 0x00004000,
+
     /* The input device is virtual (not a real device, not part of UI configuration). */
     VIRTUAL = 0x40000000,
 
@@ -242,6 +248,12 @@
     virtual void cancelVibrate(int32_t deviceId) = 0;
     virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
 
+    /* Query battery level. */
+    virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) const = 0;
+
+    /* Query battery status. */
+    virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) const = 0;
+
     /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
     virtual void requestReopenDevices() = 0;
 
@@ -404,6 +416,10 @@
 
     void monitor() override final;
 
+    std::optional<int32_t> getBatteryCapacity(int32_t deviceId) const override final;
+
+    std::optional<int32_t> getBatteryStatus(int32_t deviceId) const override final;
+
     bool isDeviceEnabled(int32_t deviceId) override final;
 
     status_t enableDevice(int32_t deviceId) override final;
@@ -442,6 +458,10 @@
         bool ffEffectPlaying;
         int16_t ffEffectId; // initially -1
 
+        // The paths are invalid when .empty() returns true
+        std::filesystem::path sysfsRootPath;
+        std::filesystem::path sysfsBatteryPath;
+
         int32_t controllerNumber;
 
         Device(int fd, int32_t id, const std::string& path,
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 5af76b7..e4186c8 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -92,6 +92,9 @@
     void disableSensor(InputDeviceSensorType sensorType);
     void flushSensor(InputDeviceSensorType sensorType);
 
+    std::optional<int32_t> getBatteryCapacity();
+    std::optional<int32_t> getBatteryStatus();
+
     int32_t getMetaState();
     void updateMetaState(int32_t keyCode);
 
@@ -287,6 +290,12 @@
 
     inline std::vector<int32_t> getVibratorIds() { return mEventHub->getVibratorIds(mId); }
 
+    inline std::optional<int32_t> getBatteryCapacity() {
+        return mEventHub->getBatteryCapacity(mId);
+    }
+
+    inline std::optional<int32_t> getBatteryStatus() { return mEventHub->getBatteryStatus(mId); }
+
     inline bool hasAbsoluteAxis(int32_t code) const {
         RawAbsoluteAxisInfo info;
         mEventHub->getAbsoluteAxisInfo(mId, code, &info);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 7be932a..e2558bc 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -95,6 +95,10 @@
 
     void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) override;
 
+    std::optional<int32_t> getBatteryCapacity(int32_t deviceId) override;
+
+    std::optional<int32_t> getBatteryStatus(int32_t deviceId) override;
+
 protected:
     // These members are protected so they can be instrumented by test cases.
     virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
new file mode 100644
index 0000000..afdc5ab
--- /dev/null
+++ b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../Macros.h"
+
+#include "BatteryInputMapper.h"
+
+namespace android {
+
+BatteryInputMapper::BatteryInputMapper(InputDeviceContext& deviceContext)
+      : InputMapper(deviceContext) {}
+
+uint32_t BatteryInputMapper::getSources() {
+    return 0;
+}
+
+void BatteryInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+    InputMapper::populateDeviceInfo(info);
+
+    info->setHasBattery(true);
+}
+
+void BatteryInputMapper::process(const RawEvent* rawEvent) {}
+
+std::optional<int32_t> BatteryInputMapper::getBatteryCapacity() {
+    return getDeviceContext().getBatteryCapacity();
+}
+
+std::optional<int32_t> BatteryInputMapper::getBatteryStatus() {
+    return getDeviceContext().getBatteryStatus();
+}
+
+void BatteryInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Battery Input Mapper:\n";
+    dump += getBatteryCapacity().has_value()
+            ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity().value())
+            : StringPrintf(INDENT3 "Capacity: Unknown");
+
+    std::string status;
+    switch (getBatteryStatus().value_or(BATTERY_STATUS_UNKNOWN)) {
+        case BATTERY_STATUS_CHARGING:
+            status = "Charging";
+            break;
+        case BATTERY_STATUS_DISCHARGING:
+            status = "Discharging";
+            break;
+        case BATTERY_STATUS_NOT_CHARGING:
+            status = "Not charging";
+            break;
+        case BATTERY_STATUS_FULL:
+            status = "Full";
+            break;
+        default:
+            status = "Unknown";
+    }
+    dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str());
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.h b/services/inputflinger/reader/mapper/BatteryInputMapper.h
new file mode 100644
index 0000000..4fe373e
--- /dev/null
+++ b/services/inputflinger/reader/mapper/BatteryInputMapper.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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 _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H
+#define _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H
+
+#include "InputMapper.h"
+
+namespace android {
+
+class BatteryInputMapper : public InputMapper {
+public:
+    explicit BatteryInputMapper(InputDeviceContext& deviceContext);
+    virtual ~BatteryInputMapper(){};
+
+    uint32_t getSources() override;
+    void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+    void process(const RawEvent* rawEvent) override;
+
+    std::optional<int32_t> getBatteryCapacity() override;
+    std::optional<int32_t> getBatteryStatus() override;
+
+    void dump(std::string& dump) override;
+};
+
+} // namespace android
+
+#endif // _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 6ca6ec9..44af998 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -72,6 +72,9 @@
     virtual void disableSensor(InputDeviceSensorType sensorType);
     virtual void flushSensor(InputDeviceSensorType sensorType);
 
+    virtual std::optional<int32_t> getBatteryCapacity() { return std::nullopt; }
+    virtual std::optional<int32_t> getBatteryStatus() { return std::nullopt; }
+
     virtual int32_t getMetaState();
     virtual void updateMetaState(int32_t keyCode);
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 36da8dd..0e88312 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <BatteryInputMapper.h>
 #include <CursorInputMapper.h>
 #include <InputDevice.h>
 #include <InputMapper.h>
@@ -67,6 +68,8 @@
 static constexpr int32_t FIRST_TRACKING_ID = 0;
 static constexpr int32_t SECOND_TRACKING_ID = 1;
 static constexpr int32_t THIRD_TRACKING_ID = 2;
+static constexpr int32_t BATTERY_STATUS = 4;
+static constexpr int32_t BATTERY_CAPACITY = 66;
 
 // Error tolerance for floating point assertions.
 static const float EPSILON = 0.001f;
@@ -863,6 +866,10 @@
 
     std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
 
+    std::optional<int32_t> getBatteryCapacity(int32_t) const override { return BATTERY_CAPACITY; }
+
+    std::optional<int32_t> getBatteryStatus(int32_t) const override { return BATTERY_STATUS; }
+
     virtual bool isExternal(int32_t) const {
         return false;
     }
@@ -1924,6 +1931,52 @@
     ASSERT_EQ(mReader->getVibratorIds(deviceId).size(), 2U);
 }
 
+class FakeBatteryInputMapper : public FakeInputMapper {
+public:
+    FakeBatteryInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
+          : FakeInputMapper(deviceContext, sources) {}
+
+    std::optional<int32_t> getBatteryCapacity() override {
+        return getDeviceContext().getBatteryCapacity();
+    }
+
+    std::optional<int32_t> getBatteryStatus() override {
+        return getDeviceContext().getBatteryStatus();
+    }
+};
+
+TEST_F(InputReaderTest, BatteryGetCapacity) {
+    constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+    constexpr int32_t eventHubId = 1;
+    const char* DEVICE_LOCATION = "BLUETOOTH";
+    std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+    FakeBatteryInputMapper& mapper =
+            device->addMapper<FakeBatteryInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+    mReader->pushNextDevice(device);
+
+    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+    ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
+
+    ASSERT_EQ(mReader->getBatteryCapacity(deviceId), BATTERY_CAPACITY);
+}
+
+TEST_F(InputReaderTest, BatteryGetStatus) {
+    constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+    constexpr int32_t eventHubId = 1;
+    const char* DEVICE_LOCATION = "BLUETOOTH";
+    std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+    FakeBatteryInputMapper& mapper =
+            device->addMapper<FakeBatteryInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+    mReader->pushNextDevice(device);
+
+    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+    ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
+
+    ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS);
+}
+
 // --- InputReaderIntegrationTest ---
 
 // These tests create and interact with the InputReader only through its interface.
@@ -2799,6 +2852,32 @@
     mapper.flushSensor(InputDeviceSensorType::GYROSCOPE);
 }
 
+// --- BatteryInputMapperTest ---
+class BatteryInputMapperTest : public InputMapperTest {
+protected:
+    void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::BATTERY); }
+};
+
+TEST_F(BatteryInputMapperTest, GetSources) {
+    BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
+
+    ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources());
+}
+
+TEST_F(BatteryInputMapperTest, GetBatteryCapacity) {
+    BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
+
+    ASSERT_TRUE(mapper.getBatteryCapacity());
+    ASSERT_EQ(*mapper.getBatteryCapacity(), BATTERY_CAPACITY);
+}
+
+TEST_F(BatteryInputMapperTest, GetBatteryStatus) {
+    BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>();
+
+    ASSERT_TRUE(mapper.getBatteryStatus());
+    ASSERT_EQ(*mapper.getBatteryStatus(), BATTERY_STATUS);
+}
+
 // --- KeyboardInputMapperTest ---
 
 class KeyboardInputMapperTest : public InputMapperTest {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 39ae2fd..ec81ff7 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -377,7 +377,7 @@
                displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
-        const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
+        const nsecs_t actualPresentTime = display->getRefreshTimestamp();
         mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime);
         mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                                actualPresentTime,
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 32e6b10..5219787 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -384,8 +384,8 @@
     return NO_ERROR;
 }
 
-void BufferQueueLayer::setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) {
-    mFrameTimelineVsyncId = frameTimelineVsyncId;
+void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) {
+    mFrameTimelineInfo = frameTimelineInfo;
 }
 
 // -----------------------------------------------------------------------
@@ -445,9 +445,8 @@
         }
 
         auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId,
-                                                                     mOwnerPid, mOwnerUid, mName,
-                                                                     mName);
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid,
+                                                                     mOwnerUid, mName, mName);
         surfaceFrame->setActualQueueTime(systemTime());
 
         mQueueItems.push_back({item, surfaceFrame});
@@ -485,9 +484,8 @@
         }
 
         auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId,
-                                                                     mOwnerPid, mOwnerUid, mName,
-                                                                     mName);
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid,
+                                                                     mOwnerUid, mName, mName);
         surfaceFrame->setActualQueueTime(systemTime());
         mQueueItems[mQueueItems.size() - 1].item = item;
         mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 0e8fdbe..41ff012 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -101,7 +101,7 @@
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
-    void setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) override;
+    void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override;
 
     sp<Layer> createClone() override;
 
@@ -145,10 +145,10 @@
 
     sp<ContentsChangedListener> mContentsChangedListener;
 
-    // The last vsync id received on this layer. This will be used when we get
+    // The last vsync info received on this layer. This will be used when we get
     // a buffer to correlate the buffer with the vsync id. Can only be accessed
     // with the SF state lock held.
-    std::optional<int64_t> mFrameTimelineVsyncId;
+    FrameTimelineInfo mFrameTimelineInfo;
 
     // Keeps track of the time SF latched the last buffer from this layer.
     // Used in buffer stuffing analysis in FrameTimeline.
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 0cc15c2..3dc62e3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -216,8 +216,7 @@
     // Returns true if the most recent Transaction applied to CurrentState will be presented.
     return (getSidebandStreamChanged() || getAutoRefresh() ||
             (mCurrentState.modified &&
-             (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr))) &&
-        !mLayerDetached;
+             (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr)));
 }
 
 /* TODO: vhau uncomment once deferred transaction migration complete in
@@ -461,11 +460,6 @@
     return willPresent;
 }
 
-void BufferStateLayer::forceSendCallbacks() {
-    mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
-            mCurrentState.callbackHandles, std::vector<JankData>());
-}
-
 bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
     mCurrentState.transparentRegionHint = transparent;
     mCurrentState.modified = true;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index f638caa..b93d567 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -80,7 +80,6 @@
     bool setApi(int32_t api) override;
     bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
     bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
-    void forceSendCallbacks() override;
     bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
                        nsecs_t requestedPresentTime) override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index 6559ed8..4502eee 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <ui/Size.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
@@ -71,7 +72,7 @@
 
     virtual void dumpAsString(String8& result) const = 0;
 
-    virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
+    virtual void resizeBuffers(const ui::Size&) = 0;
 
     virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
index 31b5f95..168e433 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/DisplaySurface.h>
 #include <gmock/gmock.h>
+#include <ui/Size.h>
 #include <utils/String8.h>
 
 namespace android::compositionengine::mock {
@@ -32,7 +33,7 @@
     MOCK_METHOD0(advanceFrame, status_t());
     MOCK_METHOD0(onFrameCommitted, void());
     MOCK_CONST_METHOD1(dumpAsString, void(String8& result));
-    MOCK_METHOD2(resizeBuffers, void(uint32_t, uint32_t));
+    MOCK_METHOD1(resizeBuffers, void(const ui::Size&));
     MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index b47f7fd..3bef77d 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -96,8 +96,7 @@
 }
 
 void RenderSurface::setDisplaySize(const ui::Size& size) {
-    mDisplaySurface->resizeBuffers(static_cast<uint32_t>(size.width),
-                                   static_cast<uint32_t>(size.height));
+    mDisplaySurface->resizeBuffers(size);
     mSize = size;
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 3133e90..ab00385 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -85,16 +85,15 @@
     MOCK_CONST_METHOD0(updatesDeviceProductInfoOnHotplugReconnect, bool());
     MOCK_METHOD2(onVsync, bool(hal::HWDisplayId, int64_t));
     MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync));
-    MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(PhysicalDisplayId));
     MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getModes, DisplayModes(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getActiveMode, DisplayModePtr(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getModes, std::vector<HWComposer::HWCDisplayMode>(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getActiveMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
     MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
     MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
     MOCK_CONST_METHOD0(isUsingVrComposer, bool());
     MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId));
     MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(PhysicalDisplayId));
+    MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*));
     MOCK_METHOD4(setActiveModeWithConstraints,
                  status_t(PhysicalDisplayId, hal::HWConfigId,
                           const hal::VsyncPeriodChangeConstraints&,
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index cd39733..5ef5d7b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -119,9 +119,10 @@
  */
 
 TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) {
-    EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1);
+    const ui::Size size(640, 480);
+    EXPECT_CALL(*mDisplaySurface, resizeBuffers(size)).Times(1);
 
-    mSurface.setDisplaySize(ui::Size(640, 480));
+    mSurface.setDisplaySize(size);
 }
 
 /*
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b4a3ed1..a785968 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -179,6 +179,31 @@
     return nullptr;
 }
 
+nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
+    const auto physicalId = getPhysicalId();
+    if (!mHwComposer.isConnected(physicalId)) {
+        return 0;
+    }
+
+    nsecs_t vsyncPeriod;
+    const auto status = mHwComposer.getDisplayVsyncPeriod(physicalId, &vsyncPeriod);
+    if (status == NO_ERROR) {
+        return vsyncPeriod;
+    }
+
+    return getActiveMode()->getFps().getPeriodNsecs();
+}
+
+nsecs_t DisplayDevice::getRefreshTimestamp() const {
+    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+    const auto vsyncPeriodNanos = getVsyncPeriodFromHWC();
+    return now - ((now - mLastHwVsync) % vsyncPeriodNanos);
+}
+
+void DisplayDevice::onVsync(nsecs_t timestamp) {
+    mLastHwVsync = timestamp;
+}
+
 ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
     return mCompositionDisplay->getState().dataspace;
 }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 6f07964..b4db933 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -176,6 +176,10 @@
     // set-top boxes after a hotplug reconnect.
     DisplayModePtr getMode(DisplayModeId) const;
 
+    void onVsync(nsecs_t timestamp);
+    nsecs_t getVsyncPeriodFromHWC() const;
+    nsecs_t getRefreshTimestamp() const;
+
     // release HWC resources (if any) for removable displays
     void disconnect();
 
@@ -207,6 +211,8 @@
     DisplayModeId mActiveModeId;
     const DisplayModes mSupportedModes;
 
+    std::atomic<nsecs_t> mLastHwVsync = 0;
+
     // TODO(b/74619554): Remove special cases for primary display.
     const bool mIsPrimary;
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 61c1b61..31d1245 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -22,6 +22,7 @@
 
 #include <android-base/stringprintf.h>
 #include <android/configuration.h>
+#include <ui/Size.h>
 #include <utils/Timers.h>
 
 #include <cstddef>
@@ -113,6 +114,7 @@
 
     int32_t getWidth() const { return mWidth; }
     int32_t getHeight() const { return mHeight; }
+    ui::Size getSize() const { return {mWidth, mHeight}; }
     Fps getFps() const { return mFps; }
     nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); }
     float getDpiX() const { return mDpiX; }
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 3e856bb..f7fc162 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -58,11 +58,10 @@
 
 FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
                                        const sp<IGraphicBufferConsumer>& consumer,
-                                       uint32_t maxWidth, uint32_t maxHeight)
+                                       const ui::Size& size, const ui::Size& maxSize)
       : ConsumerBase(consumer),
         mDisplayId(displayId),
-        mMaxWidth(maxWidth),
-        mMaxHeight(maxHeight),
+        mMaxSize(maxSize),
         mCurrentBufferSlot(-1),
         mCurrentBuffer(),
         mCurrentFence(Fence::NO_FENCE),
@@ -77,15 +76,14 @@
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
-    const auto& activeMode = mHwc.getActiveMode(displayId);
-    ui::Size limitedSize = limitFramebufferSize(activeMode->getWidth(), activeMode->getHeight());
+    const auto limitedSize = limitFramebufferSize(size);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
     mConsumer->setMaxAcquiredBufferCount(
             SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
-void FramebufferSurface::resizeBuffers(uint32_t width, uint32_t height) {
-    ui::Size limitedSize = limitFramebufferSize(width, height);
+void FramebufferSurface::resizeBuffers(const ui::Size& newSize) {
+    const auto limitedSize = limitFramebufferSize(newSize);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
 }
 
@@ -181,24 +179,24 @@
     }
 }
 
-ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) {
-    ui::Size framebufferSize(width, height);
-    bool wasLimited = true;
-    if (width > mMaxWidth && mMaxWidth != 0) {
-        float aspectRatio = float(width) / float(height);
-        framebufferSize.height = mMaxWidth / aspectRatio;
-        framebufferSize.width = mMaxWidth;
+ui::Size FramebufferSurface::limitFramebufferSize(const ui::Size& size) {
+    ui::Size limitedSize = size;
+    bool wasLimited = false;
+    if (size.width > mMaxSize.width && mMaxSize.width != 0) {
+        const float aspectRatio = static_cast<float>(size.width) / size.height;
+        limitedSize.height = mMaxSize.width / aspectRatio;
+        limitedSize.width = mMaxSize.width;
         wasLimited = true;
     }
-    if (height > mMaxHeight && mMaxHeight != 0) {
-        float aspectRatio = float(width) / float(height);
-        framebufferSize.height = mMaxHeight;
-        framebufferSize.width = mMaxHeight * aspectRatio;
+    if (size.height > mMaxSize.height && mMaxSize.height != 0) {
+        const float aspectRatio = static_cast<float>(size.width) / size.height;
+        limitedSize.height = mMaxSize.height;
+        limitedSize.width = mMaxSize.height * 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;
+             limitedSize.width, limitedSize.height, size.width, size.height);
+    return limitedSize;
 }
 
 void FramebufferSurface::dumpAsString(String8& result) const {
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 759943a..5d1e131 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -41,8 +41,8 @@
 class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
 public:
     FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
-                       const sp<IGraphicBufferConsumer>& consumer, uint32_t maxWidth,
-                       uint32_t maxHeight);
+                       const sp<IGraphicBufferConsumer>& consumer, const ui::Size& size,
+                       const ui::Size& maxSize);
 
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
@@ -50,7 +50,7 @@
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
 
-    virtual void resizeBuffers(uint32_t width, uint32_t height);
+    virtual void resizeBuffers(const ui::Size&) override;
 
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
@@ -62,7 +62,7 @@
     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);
+    ui::Size limitFramebufferSize(const ui::Size&);
 
     // nextBuffer waits for and then latches the next buffer from the
     // BufferQueue and releases the previously latched buffer to the
@@ -74,11 +74,7 @@
 
     // 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;
+    const ui::Size mMaxSize;
 
     // mCurrentBufferIndex is the slot index of the current buffer or
     // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 46dc54e..b9a8e4b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -223,8 +223,6 @@
                  __FUNCTION__, to_string(*displayId).c_str());
 
     {
-        std::lock_guard lock(displayData.lastHwVsyncLock);
-
         // There have been reports of HWCs that signal several vsync events
         // with the same timestamp when turning the display off and on. This
         // is a bug in the HWC implementation, but filter the extra events
@@ -295,11 +293,10 @@
                                                   hal::DisplayType::PHYSICAL);
     newDisplay->setConnected(true);
     displayData.hwcDisplay = std::move(newDisplay);
-    loadModes(displayData, hwcDisplayId);
 }
 
 int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
-                                 hal::Attribute attribute) {
+                                 hal::Attribute attribute) const {
     int32_t value = 0;
     auto error = static_cast<hal::Error>(
             mComposer->getDisplayAttribute(hwcDisplayId, configId, attribute, &value));
@@ -308,30 +305,6 @@
     return value;
 }
 
-void HWComposer::loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId) {
-    ALOGV("[HWC display %" PRIu64 "] %s", hwcDisplayId, __FUNCTION__);
-
-    std::vector<hal::HWConfigId> configIds;
-    auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds));
-    RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId));
-
-    displayData.modes.clear();
-    for (auto configId : configIds) {
-        auto mode = DisplayMode::Builder(configId)
-                            .setId(DisplayModeId(displayData.modes.size()))
-                            .setWidth(getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH))
-                            .setHeight(getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT))
-                            .setVsyncPeriod(getAttribute(hwcDisplayId, configId,
-                                                         hal::Attribute::VSYNC_PERIOD))
-                            .setDpiX(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X))
-                            .setDpiY(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y))
-                            .setConfigGroup(getAttribute(hwcDisplayId, configId,
-                                                         hal::Attribute::CONFIG_GROUP))
-                            .build();
-        displayData.modes.push_back(std::move(mode));
-    }
-}
-
 HWC2::Layer* HWComposer::createLayer(HalDisplayId displayId) {
     RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
 
@@ -348,55 +321,50 @@
     RETURN_IF_HWC_ERROR(error, displayId);
 }
 
-nsecs_t HWComposer::getRefreshTimestamp(PhysicalDisplayId displayId) const {
-    RETURN_IF_INVALID_DISPLAY(displayId, 0);
-    const auto& displayData = mDisplayData.at(displayId);
-    // this returns the last refresh timestamp.
-    // if the last one is not available, we estimate it based on
-    // the refresh period and whatever closest timestamp we have.
-    std::lock_guard lock(displayData.lastHwVsyncLock);
-    nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId);
-    return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos);
-}
-
 bool HWComposer::isConnected(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, false);
     return mDisplayData.at(displayId).hwcDisplay->isConnected();
 }
 
-DisplayModes HWComposer::getModes(PhysicalDisplayId displayId) const {
+std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
-    // We cache the modes when the DisplayData is created on hotplug. If the modes need to
-    // change HWC will send a hotplug event which will recreate displayData.
-    return mDisplayData.at(displayId).modes;
+    const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId();
+    std::vector<hal::HWConfigId> configIds;
+    auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds));
+    RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {});
+
+    std::vector<HWCDisplayMode> modes;
+    modes.reserve(configIds.size());
+    for (auto configId : configIds) {
+        modes.push_back(HWCDisplayMode{
+                .hwcId = configId,
+                .width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH),
+                .height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT),
+                .vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD),
+                .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X),
+                .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y),
+                .configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP),
+        });
+    }
+
+    return modes;
 }
 
-DisplayModePtr HWComposer::getActiveMode(PhysicalDisplayId displayId) const {
-    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
+std::optional<hal::HWConfigId> HWComposer::getActiveMode(PhysicalDisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt);
 
     const auto hwcId = *fromPhysicalDisplayId(displayId);
     ALOGV("[%" PRIu64 "] getActiveMode", hwcId);
     hal::HWConfigId configId;
     auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId));
 
-    const auto& modes = mDisplayData.at(displayId).modes;
     if (error == hal::Error::BAD_CONFIG) {
         LOG_DISPLAY_ERROR(displayId, "No active mode");
-        return nullptr;
+        return std::nullopt;
     }
 
-    RETURN_IF_HWC_ERROR(error, displayId, nullptr);
-
-    const auto it = std::find_if(modes.begin(), modes.end(),
-                                 [configId](auto mode) { return mode->getHwcId() == configId; });
-    if (it == modes.end()) {
-        LOG_DISPLAY_ERROR(displayId, "Unknown mode");
-        return nullptr;
-    }
-
-    return *it;
+    return configId;
 }
 
 // Composer 2.4
@@ -421,27 +389,20 @@
     return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
 }
 
-nsecs_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId) const {
+status_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId,
+                                           nsecs_t* outVsyncPeriod) const {
     RETURN_IF_INVALID_DISPLAY(displayId, 0);
 
-    if (isVsyncPeriodSwitchSupported(displayId)) {
-        const auto hwcId = *fromPhysicalDisplayId(displayId);
-        Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0;
-        auto error =
-                static_cast<hal::Error>(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos));
-        RETURN_IF_HWC_ERROR(error, displayId, 0);
-        return static_cast<nsecs_t>(vsyncPeriodNanos);
+    if (!isVsyncPeriodSwitchSupported(displayId)) {
+        return INVALID_OPERATION;
     }
-
-    // Get the default vsync period
-    auto mode = getActiveMode(displayId);
-
-    if (!mode) {
-        // HWC has updated the display modes and hasn't notified us yet.
-        RETURN_IF_HWC_ERROR(hal::Error::BAD_CONFIG, displayId, 0);
-    }
-
-    return mode->getVsyncPeriod();
+    const auto hwcId = *fromPhysicalDisplayId(displayId);
+    Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0;
+    auto error =
+            static_cast<hal::Error>(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos));
+    RETURN_IF_HWC_ERROR(error, displayId, 0);
+    *outVsyncPeriod = static_cast<nsecs_t>(vsyncPeriodNanos);
+    return NO_ERROR;
 }
 
 std::vector<ui::ColorMode> HWComposer::getColorModes(PhysicalDisplayId displayId) const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 1ffe276..f9c8e2e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -83,6 +83,16 @@
         ClientTargetProperty clientTargetProperty;
     };
 
+    struct HWCDisplayMode {
+        hal::HWConfigId hwcId;
+        int32_t width = -1;
+        int32_t height = -1;
+        nsecs_t vsyncPeriod = -1;
+        int32_t dpiX = -1;
+        int32_t dpiY = -1;
+        int32_t configGroup = -1;
+    };
+
     virtual ~HWComposer();
 
     virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
@@ -182,12 +192,11 @@
     virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0;
     virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0;
 
-    virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0;
     virtual bool isConnected(PhysicalDisplayId) const = 0;
 
-    virtual DisplayModes getModes(PhysicalDisplayId) const = 0;
+    virtual std::vector<HWCDisplayMode> getModes(PhysicalDisplayId) const = 0;
 
-    virtual DisplayModePtr getActiveMode(PhysicalDisplayId) const = 0;
+    virtual std::optional<hal::HWConfigId> getActiveMode(PhysicalDisplayId) const = 0;
 
     virtual std::vector<ui::ColorMode> getColorModes(PhysicalDisplayId) const = 0;
 
@@ -197,7 +206,8 @@
     // Composer 2.4
     virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0;
-    virtual nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const = 0;
+    virtual status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
+                                           nsecs_t* outVsyncPeriod) const = 0;
     virtual status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId,
                                                   const hal::VsyncPeriodChangeConstraints&,
                                                   hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
@@ -314,12 +324,11 @@
     bool onVsync(hal::HWDisplayId, int64_t timestamp) override;
     void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override;
 
-    nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override;
     bool isConnected(PhysicalDisplayId) const override;
 
-    DisplayModes getModes(PhysicalDisplayId) const override;
+    std::vector<HWCDisplayMode> getModes(PhysicalDisplayId) const override;
 
-    DisplayModePtr getActiveMode(PhysicalDisplayId) const override;
+    std::optional<hal::HWConfigId> getActiveMode(PhysicalDisplayId) const override;
 
     std::vector<ui::ColorMode> getColorModes(PhysicalDisplayId) const override;
 
@@ -328,7 +337,8 @@
     // Composer 2.4
     DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
-    nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId displayId) const override;
+    status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
+                                   nsecs_t* outVsyncPeriod) const override;
     status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId,
                                           const hal::VsyncPeriodChangeConstraints&,
                                           hal::VsyncPeriodChangeTimeline* outTimeline) override;
@@ -365,7 +375,6 @@
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
         buffer_handle_t outbufHandle = nullptr;
         sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
-        DisplayModes modes;
 
         bool validateWasSkipped;
         hal::Error presentError;
@@ -375,8 +384,7 @@
         std::mutex vsyncEnabledLock;
         hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
 
-        mutable std::mutex lastHwVsyncLock;
-        nsecs_t lastHwVsync GUARDED_BY(lastHwVsyncLock) = 0;
+        nsecs_t lastHwVsync = 0;
     };
 
     std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
@@ -384,8 +392,7 @@
     bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const;
 
     int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
-                         hal::Attribute attribute);
-    void loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId);
+                         hal::Attribute attribute) const;
 
     void loadCapabilities();
     void loadLayerMetadataSupport();
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 2ac67cb..e26ab11 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -291,11 +291,11 @@
 void VirtualDisplaySurface::dumpAsString(String8& /* result */) const {
 }
 
-void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) {
-    mQueueBufferOutput.width = w;
-    mQueueBufferOutput.height = h;
-    mSinkBufferWidth = w;
-    mSinkBufferHeight = h;
+void VirtualDisplaySurface::resizeBuffers(const ui::Size& newSize) {
+    mQueueBufferOutput.width = newSize.width;
+    mQueueBufferOutput.height = newSize.height;
+    mSinkBufferWidth = newSize.width;
+    mSinkBufferHeight = newSize.height;
 }
 
 const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fba0e3b..bbb6306 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -90,7 +90,7 @@
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
-    virtual void resizeBuffers(const uint32_t w, const uint32_t h);
+    virtual void resizeBuffers(const ui::Size&) override;
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
 private:
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 17d1f3b..3743716 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -275,13 +275,15 @@
     return ++mTraceCookie;
 }
 
-SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
-                           std::string debugName, PredictionState predictionState,
+SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid,
+                           uid_t ownerUid, std::string layerName, std::string debugName,
+                           PredictionState predictionState,
                            frametimeline::TimelineItem&& predictions,
                            std::shared_ptr<TimeStats> timeStats,
                            JankClassificationThresholds thresholds,
                            TraceCookieCounter* traceCookieCounter)
-      : mToken(token),
+      : mToken(frameTimelineInfo.vsyncId),
+        mInputEventId(frameTimelineInfo.inputEventId),
         mOwnerPid(ownerPid),
         mOwnerUid(ownerUid),
         mLayerName(std::move(layerName)),
@@ -295,27 +297,27 @@
         mTraceCookieCounter(*traceCookieCounter) {}
 
 void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mActuals.startTime = actualStartTime;
 }
 
 void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mActualQueueTime = actualQueueTime;
 }
 void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
 }
 
 void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mPresentState = presentState;
     mLastLatchTime = lastLatchTime;
 }
 
 std::optional<int32_t> SurfaceFrame::getJankType() const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     if (mActuals.presentTime == 0) {
         return std::nullopt;
     }
@@ -323,32 +325,32 @@
 }
 
 nsecs_t SurfaceFrame::getBaseTime() const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     return getMinTime(mPredictionState, mPredictions, mActuals);
 }
 
 TimelineItem SurfaceFrame::getActuals() const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     return mActuals;
 }
 
 SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     return mPresentState;
 }
 
 FramePresentMetadata SurfaceFrame::getFramePresentMetadata() const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     return mFramePresentMetadata;
 }
 
 FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     return mFrameReadyMetadata;
 }
 
 void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Layer - %s", mDebugName.c_str());
     if (mJankType != JankType::None) {
@@ -387,7 +389,7 @@
 
 void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
                              nsecs_t vsyncPeriod) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     if (mPresentState != PresentState::Presented) {
         // No need to update dropped buffers
         return;
@@ -479,6 +481,9 @@
     mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
 }
 
+/**
+ * TODO(b/178637512): add inputEventId to the perfetto trace.
+ */
 void SurfaceFrame::trace(int64_t displayFrameToken) {
     using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
 
@@ -486,12 +491,12 @@
     bool missingToken = false;
     // Expected timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
+        std::scoped_lock lock(mMutex);
+        if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
             ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str());
             missingToken = true;
             return;
-        } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) {
+        } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
             ALOGD("Cannot trace SurfaceFrame  - %s with invalid displayFrameToken",
                   mLayerName.c_str());
             missingToken = true;
@@ -521,7 +526,7 @@
 
     // Expected timeline end
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
-        std::lock_guard<std::mutex> lock(mMutex);
+        std::scoped_lock lock(mMutex);
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
         packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime));
@@ -535,7 +540,7 @@
     int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
     // Actual timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
-        std::lock_guard<std::mutex> lock(mMutex);
+        std::scoped_lock lock(mMutex);
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
         // Actual start time is not yet available, so use expected start instead
@@ -566,7 +571,7 @@
     });
     // Actual timeline end
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
-        std::lock_guard<std::mutex> lock(mMutex);
+        std::scoped_lock lock(mMutex);
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
         packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
@@ -582,7 +587,7 @@
 
 int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
     ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     const int64_t assignedToken = mCurrentToken++;
     mPredictions[assignedToken] = {systemTime(), predictions};
     flushTokens(systemTime());
@@ -590,7 +595,7 @@
 }
 
 std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) const {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     auto predictionsIterator = mPredictions.find(token);
     if (predictionsIterator != mPredictions.end()) {
         return predictionsIterator->second.predictions;
@@ -634,26 +639,28 @@
 }
 
 std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
-        std::optional<int64_t> token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
-        std::string debugName) {
+        const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
+        std::string layerName, std::string debugName) {
     ATRACE_CALL();
-    if (!token) {
-        return std::make_shared<SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid,
-                                              ownerUid, std::move(layerName), std::move(debugName),
+    if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
+        return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid,
+                                              std::move(layerName), std::move(debugName),
                                               PredictionState::None, TimelineItem(), mTimeStats,
                                               mJankClassificationThresholds, &mTraceCookieCounter);
     }
-    std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
+    std::optional<TimelineItem> predictions =
+            mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId);
     if (predictions) {
-        return std::make_shared<SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
-                                              std::move(debugName), PredictionState::Valid,
-                                              std::move(*predictions), mTimeStats,
-                                              mJankClassificationThresholds, &mTraceCookieCounter);
+        return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid,
+                                              std::move(layerName), std::move(debugName),
+                                              PredictionState::Valid, std::move(*predictions),
+                                              mTimeStats, mJankClassificationThresholds,
+                                              &mTraceCookieCounter);
     }
-    return std::make_shared<SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
-                                          std::move(debugName), PredictionState::Expired,
-                                          TimelineItem(), mTimeStats, mJankClassificationThresholds,
-                                          &mTraceCookieCounter);
+    return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid,
+                                          std::move(layerName), std::move(debugName),
+                                          PredictionState::Expired, TimelineItem(), mTimeStats,
+                                          mJankClassificationThresholds, &mTraceCookieCounter);
 }
 
 FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
@@ -669,13 +676,13 @@
 
 void FrameTimeline::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame) {
     ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
 }
 
 void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
     ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
                                      mTokenManager.getPredictionsForToken(token), wakeUpTime);
 }
@@ -683,7 +690,7 @@
 void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
                                  const std::shared_ptr<FenceTime>& presentFence) {
     ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
     mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
     flushPendingPresentFences();
@@ -826,7 +833,7 @@
     // Expected timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         auto packet = ctx.NewTracePacket();
-        if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
+        if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
             ALOGD("Cannot trace DisplayFrame with invalid token");
             missingToken = true;
             return;
@@ -999,7 +1006,7 @@
 }
 
 void FrameTimeline::dumpAll(std::string& result) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
     nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime();
     for (size_t i = 0; i < mDisplayFrames.size(); i++) {
@@ -1009,7 +1016,7 @@
 }
 
 void FrameTimeline::dumpJank(std::string& result) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
     nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime();
     for (size_t i = 0; i < mDisplayFrames.size(); i++) {
         mDisplayFrames[i]->dumpJank(result, baseTime, static_cast<int>(i));
@@ -1031,7 +1038,7 @@
 }
 
 void FrameTimeline::setMaxDisplayFrames(uint32_t size) {
-    std::lock_guard<std::mutex> lock(mMutex);
+    std::scoped_lock lock(mMutex);
 
     // The size can either increase or decrease, clear everything, to be consistent
     mDisplayFrames.clear();
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index ed38cc6..54e8efb 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -154,10 +154,10 @@
 
     // Only FrameTimeline can construct a SurfaceFrame as it provides Predictions(through
     // TokenManager), Thresholds and TimeStats pointer.
-    SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
-                 std::string debugName, PredictionState predictionState, TimelineItem&& predictions,
-                 std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
-                 TraceCookieCounter* traceCookieCounter);
+    SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
+                 std::string layerName, std::string debugName, PredictionState predictionState,
+                 TimelineItem&& predictions, std::shared_ptr<TimeStats> timeStats,
+                 JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter);
     ~SurfaceFrame() = default;
 
     // Returns std::nullopt if the frame hasn't been classified yet.
@@ -166,6 +166,7 @@
 
     // Functions called by SF
     int64_t getToken() const { return mToken; };
+    int32_t getInputEventId() const { return mInputEventId; };
     TimelineItem getPredictions() const { return mPredictions; };
     // Actual timestamps of the app are set individually at different functions.
     // Start time (if the app provides) and Queue time are accessible after queueing the frame,
@@ -198,6 +199,7 @@
 
 private:
     const int64_t mToken;
+    const int32_t mInputEventId;
     const pid_t mOwnerPid;
     const uid_t mOwnerUid;
     const std::string mLayerName;
@@ -243,10 +245,9 @@
 
     // Create a new surface frame, set the predictions based on a token and return it to the caller.
     // Debug name is the human-readable debugging string for dumpsys.
-    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(std::optional<int64_t> token,
-                                                                     pid_t ownerPid, uid_t ownerUid,
-                                                                     std::string layerName,
-                                                                     std::string debugName) = 0;
+    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
+            const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
+            std::string layerName, std::string debugName) = 0;
 
     // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
     // composited into one display frame.
@@ -279,7 +280,7 @@
 
 class TokenManager : public android::frametimeline::TokenManager {
 public:
-    TokenManager() : mCurrentToken(ISurfaceComposer::INVALID_VSYNC_ID + 1) {}
+    TokenManager() : mCurrentToken(FrameTimelineInfo::INVALID_VSYNC_ID + 1) {}
     ~TokenManager() = default;
 
     int64_t generateTokenForPredictions(TimelineItem&& predictions) override;
@@ -353,7 +354,7 @@
     private:
         void dump(std::string& result, nsecs_t baseTime) const;
 
-        int64_t mToken = ISurfaceComposer::INVALID_VSYNC_ID;
+        int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID;
 
         /* Usage of TimelineItem w.r.t SurfaceFlinger
          * startTime    Time when SurfaceFlinger wakes up to handle transactions and buffer updates
@@ -393,10 +394,9 @@
     ~FrameTimeline() = default;
 
     frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
-    std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(std::optional<int64_t> token,
-                                                             pid_t ownerPid, uid_t ownerUid,
-                                                             std::string layerName,
-                                                             std::string debugName) override;
+    std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
+            const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
+            std::string layerName, std::string debugName) override;
     void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
     void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override;
     void setSfPresent(nsecs_t sfPresentTime,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 177a81a..08a5f0f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -129,7 +129,7 @@
     mCurrentState.shadowRadius = 0.f;
     mCurrentState.treeHasFrameRateVote = false;
     mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID;
-    mCurrentState.frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+    mCurrentState.frameTimelineInfo = {};
     mCurrentState.postTime = -1;
 
     if (args.flags & ISurfaceComposerClient::eNoColorFill) {
@@ -907,14 +907,10 @@
     }
 
     if (stateUpdateAvailable) {
-        const auto vsyncId =
-                stateToCommit->frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID
-                ? std::nullopt
-                : std::make_optional(stateToCommit->frameTimelineVsyncId);
-
         mSurfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(vsyncId, mOwnerPid, mOwnerUid,
-                                                                     mName, mTransactionName);
+                mFlinger->mFrameTimeline
+                        ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid,
+                                                     mOwnerUid, mName, mTransactionName);
         mSurfaceFrame->setActualQueueTime(stateToCommit->postTime);
         // For transactions we set the acquire fence time to the post time as we
         // don't have a buffer. For BufferStateLayer it is overridden in
@@ -1004,19 +1000,6 @@
 uint32_t Layer::doTransaction(uint32_t flags) {
     ATRACE_CALL();
 
-    if (mLayerDetached) {
-        // Ensure BLAST buffer callbacks are processed.
-        // detachChildren and mLayerDetached were implemented to avoid geometry updates
-        // to layers in the cases of animation. For BufferQueue layers buffers are still
-        // consumed as normal. This is useful as otherwise the client could get hung
-        // inevitably waiting on a buffer to return. We recreate this semantic for BufferQueue
-        // even though it is a little consistent. detachChildren is shortly slated for removal
-        // by the hierarchy mirroring work so we don't need to worry about it too much.
-        forceSendCallbacks();
-        mCurrentState.callbackHandles = {};
-        return flags;
-    }
-
     if (mChildrenChanged) {
         flags |= eVisibleRegion;
         mChildrenChanged = false;
@@ -1491,8 +1474,8 @@
     return true;
 }
 
-void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) {
-    mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId;
+void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) {
+    mCurrentState.frameTimelineInfo = info;
     mCurrentState.postTime = postTime;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -1523,12 +1506,6 @@
 
 void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
     ATRACE_CALL();
-    if (mLayerDetached) {
-        // If the layer is detached, then we don't defer this transaction since we will not
-        // commit the pending state while the layer is detached. Adding sync points may cause
-        // the barrier layer to wait for the states to be committed before dequeuing a buffer.
-        return;
-    }
 
     mCurrentState.barrierLayer_legacy = barrierLayer;
     mCurrentState.barrierFrameNumber = frameNumber;
@@ -1814,10 +1791,6 @@
 }
 
 void Layer::reparentChildren(const sp<Layer>& newParent) {
-    if (attachChildren()) {
-        setTransactionFlags(eTransactionNeeded);
-    }
-
     for (const sp<Layer>& child : mCurrentChildren) {
         newParent->addChild(child);
     }
@@ -1853,17 +1826,6 @@
 }
 
 bool Layer::reparent(const sp<IBinder>& newParentHandle) {
-    bool callSetTransactionFlags = false;
-
-    // While layers are detached, we allow most operations
-    // and simply halt performing the actual transaction. However
-    // for reparent != null we would enter the mRemovedFromCurrentState
-    // state, regardless of whether doTransaction was called, and
-    // so we need to prevent the update here.
-    if (mLayerDetached && newParentHandle == nullptr) {
-        return false;
-    }
-
     sp<Layer> newParent;
     if (newParentHandle != nullptr) {
         auto handle = static_cast<Handle*>(newParentHandle.get());
@@ -1890,52 +1852,13 @@
         } else {
             onRemovedFromCurrentState();
         }
-
-        if (mLayerDetached) {
-            mLayerDetached = false;
-            callSetTransactionFlags = true;
-        }
     } else {
         onRemovedFromCurrentState();
     }
 
-    if (attachChildren() || callSetTransactionFlags) {
-        setTransactionFlags(eTransactionNeeded);
-    }
     return true;
 }
 
-bool Layer::detachChildren() {
-    for (const sp<Layer>& child : mCurrentChildren) {
-        sp<Client> parentClient = mClientRef.promote();
-        sp<Client> client(child->mClientRef.promote());
-        if (client != nullptr && parentClient != client) {
-            child->mLayerDetached = true;
-            child->detachChildren();
-            child->removeRemoteSyncPoints();
-        }
-    }
-
-    return true;
-}
-
-bool Layer::attachChildren() {
-    bool changed = false;
-    for (const sp<Layer>& child : mCurrentChildren) {
-        sp<Client> parentClient = mClientRef.promote();
-        sp<Client> client(child->mClientRef.promote());
-        if (client != nullptr && parentClient != client) {
-            if (child->mLayerDetached) {
-                child->mLayerDetached = false;
-                child->attachChildren();
-                changed = true;
-            }
-        }
-    }
-
-    return changed;
-}
-
 bool Layer::setColorTransform(const mat4& matrix) {
     static const mat4 identityMatrix = mat4();
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 357c4a4..4b40c8e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -304,8 +304,8 @@
         // a fixed transform hint is not set.
         ui::Transform::RotationFlags fixedTransformHint;
 
-        // The vsync id that was used to start the transaction
-        int64_t frameTimelineVsyncId;
+        // The vsync info that was used to start the transaction
+        FrameTimelineInfo frameTimelineInfo;
 
         // When the transaction was posted
         nsecs_t postTime;
@@ -434,7 +434,6 @@
     virtual bool setMetadata(const LayerMetadata& data);
     virtual void setChildrenDrawingParent(const sp<Layer>&);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
-    virtual bool detachChildren();
     virtual bool setColorTransform(const mat4& matrix);
     virtual mat4 getColorTransform() const;
     virtual bool hasColorTransform() const;
@@ -461,7 +460,6 @@
             const std::vector<sp<CallbackHandle>>& /*handles*/) {
         return false;
     };
-    virtual void forceSendCallbacks() {}
     virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
                                nsecs_t /*requestedPresentTime*/) {
         return false;
@@ -666,8 +664,6 @@
 
     bool reparentChildren(const sp<IBinder>& newParentHandle);
     void reparentChildren(const sp<Layer>& newParent);
-    bool attachChildren();
-    bool isLayerDetached() const { return mLayerDetached; }
     bool setShadowRadius(float shadowRadius);
 
     // Before color management is introduced, contents on Android have to be
@@ -869,8 +865,9 @@
 
     bool setFrameRate(FrameRate);
 
-    virtual void setFrameTimelineVsyncForBuffer(int64_t /*frameTimelineVsyncId*/) {}
-    void setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime);
+    virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
+    void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo,
+                                            nsecs_t postTime);
 
     // Creates a new handle each time, so we only expect
     // this to be called once.
@@ -1103,8 +1100,6 @@
     wp<Layer> mDrawingParent;
 
     // Can only be accessed with the SF state lock held.
-    bool mLayerDetached{false};
-    // Can only be accessed with the SF state lock held.
     bool mChildrenChanged{false};
 
     // Window types from WindowManager.LayoutParams
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 19b3d6e..9186538 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -451,7 +451,7 @@
 
     const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
     mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
-                                 true /* regionSampling */, captureListener);
+                                 true /* regionSampling */, false /* grayscale */, captureListener);
     ScreenCaptureResults captureResults = captureListener->waitForResults();
 
     std::vector<Descriptor> activeDescriptors;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index c12a7b1..f90c130 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -303,6 +303,10 @@
     std::lock_guard<std::mutex> lock(mMutex);
 
     const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate);
+    if (request != VSyncRequest::None && connection->resyncCallback) {
+        connection->resyncCallback();
+    }
+
     if (connection->vsyncRequest != request) {
         connection->vsyncRequest = request;
         mCondition.notify_all();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a6b05d0..e9b5875 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -68,6 +68,7 @@
 #include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
 #include <ui/DisplayConfig.h>
+#include <ui/DisplayId.h>
 #include <ui/DisplayInfo.h>
 #include <ui/DisplayStatInfo.h>
 #include <ui/DisplayState.h>
@@ -275,7 +276,6 @@
 const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
 const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER");
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
-const String16 sUseBackgroundBlur("android.permission.USE_BACKGROUND_BLUR");
 const String16 sDump("android.permission.DUMP");
 const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
 
@@ -333,10 +333,6 @@
             PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid);
 }
 
-bool originalCallerCanUseBlurs(int originPid, int originUid) {
-    return PermissionCache::checkPermission(sUseBackgroundBlur, originPid, originUid);
-}
-
 SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
 
 SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
@@ -1586,12 +1582,11 @@
 }
 
 nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
-    const auto displayId = getInternalDisplayIdLocked();
-    if (!displayId || !getHwComposer().isConnected(*displayId)) {
-        return 0;
+    if (const auto display = getDefaultDisplayDeviceLocked()) {
+        return display->getVsyncPeriodFromHWC();
     }
 
-    return getHwComposer().getDisplayVsyncPeriod(*displayId);
+    return 0;
 }
 
 void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
@@ -1605,6 +1600,12 @@
         return;
     }
 
+    if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) {
+        auto token = getPhysicalDisplayTokenLocked(*displayId);
+        auto display = getDisplayDeviceLocked(token);
+        display->onVsync(timestamp);
+    }
+
     if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
         return;
     }
@@ -1943,19 +1944,16 @@
 
 bool SurfaceFlinger::handleMessageTransaction() {
     ATRACE_CALL();
+
+    if (getTransactionFlags(eTransactionFlushNeeded)) {
+        flushTransactionQueues();
+    }
     uint32_t transactionFlags = peekTransactionFlags();
-
-    bool flushedATransaction = flushTransactionQueues();
-
     bool runHandleTransaction =
-            (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
-            flushedATransaction ||
-            mForceTraversal;
+            ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;
 
     if (runHandleTransaction) {
         handleTransaction(eTransactionMask);
-    } else {
-        getTransactionFlags(eTransactionFlushNeeded);
     }
 
     if (transactionFlushNeeded()) {
@@ -2223,8 +2221,7 @@
         } else if (isDisplayConnected) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
-            const nsecs_t presentTime =
-                    getHwComposer().getRefreshTimestamp(display->getPhysicalId());
+            const nsecs_t presentTime = display->getRefreshTimestamp();
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
@@ -2361,6 +2358,24 @@
     // here the transaction has been committed
 }
 
+DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const {
+    const auto hwcModes = getHwComposer().getModes(displayId);
+    DisplayModes modes;
+    size_t nextModeId = 0;
+    for (const auto& hwcMode : hwcModes) {
+        modes.push_back(DisplayMode::Builder(hwcMode.hwcId)
+                                .setId(DisplayModeId{nextModeId++})
+                                .setWidth(hwcMode.width)
+                                .setHeight(hwcMode.height)
+                                .setVsyncPeriod(hwcMode.vsyncPeriod)
+                                .setDpiX(hwcMode.dpiX)
+                                .setDpiY(hwcMode.dpiY)
+                                .setConfigGroup(hwcMode.configGroup)
+                                .build());
+    }
+    return modes;
+}
+
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
         std::optional<DisplayIdentificationInfo> info =
@@ -2374,8 +2389,14 @@
         const auto it = mPhysicalDisplayTokens.find(displayId);
 
         if (event.connection == hal::Connection::CONNECTED) {
-            auto supportedModes = getHwComposer().getModes(displayId);
-            const auto activeMode = getHwComposer().getActiveMode(displayId);
+            auto supportedModes = loadSupportedDisplayModes(displayId);
+            const auto activeModeHwcId = getHwComposer().getActiveMode(displayId);
+            LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active config");
+
+            const auto activeMode = *std::find_if(supportedModes.begin(), supportedModes.end(),
+                                                  [activeModeHwcId](const DisplayModePtr& mode) {
+                                                      return mode->getHwcId() == *activeModeHwcId;
+                                                  });
             // TODO(b/175678215) Handle the case when activeMode is not in supportedModes
 
             if (it == mPhysicalDisplayTokens.end()) {
@@ -2526,17 +2547,15 @@
 
 void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
                                          const DisplayDeviceState& state) {
-    int width = 0;
-    int height = 0;
+    ui::Size resolution(0, 0);
     ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
     if (state.physical) {
-        width = state.physical->activeMode->getWidth();
-        height = state.physical->activeMode->getHeight();
+        resolution = state.physical->activeMode->getSize();
         pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
     } else if (state.surface != nullptr) {
-        int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
+        int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width);
         ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
-        status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+        status = state.surface->query(NATIVE_WINDOW_HEIGHT, &resolution.height);
         ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
         int intPixelFormat;
         status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
@@ -2553,7 +2572,7 @@
     if (const auto& physical = state.physical) {
         builder.setPhysical({physical->id, physical->type});
     }
-    builder.setPixels(ui::Size(width, height));
+    builder.setPixels(resolution);
     builder.setPixelFormat(pixelFormat);
     builder.setIsSecure(state.isSecure);
     builder.setLayerStackId(state.layerStack);
@@ -2588,7 +2607,8 @@
         const auto physicalId = PhysicalDisplayId::tryCast(displayId);
         LOG_FATAL_IF(!physicalId);
         displaySurface = new FramebufferSurface(getHwComposer(), *physicalId, bqConsumer,
-                                                maxGraphicsWidth, maxGraphicsHeight);
+                                                state.physical->activeMode->getSize(),
+                                                ui::Size(maxGraphicsWidth, maxGraphicsHeight));
         producer = bqProducer;
     }
 
@@ -2864,7 +2884,6 @@
         });
     }
 
-    commitInputWindowCommands();
     commitTransaction();
 }
 
@@ -2905,11 +2924,6 @@
                                                                      : nullptr);
 }
 
-void SurfaceFlinger::commitInputWindowCommands() {
-    mInputWindowCommands.merge(mPendingInputWindowCommands);
-    mPendingInputWindowCommands.clear();
-}
-
 void SurfaceFlinger::updateCursorAsync() {
     compositionengine::CompositionRefreshArgs refreshArgs;
     for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
@@ -3272,17 +3286,16 @@
     mForceTraversal = true;
 }
 
-bool SurfaceFlinger::flushTransactionQueues() {
+void SurfaceFlinger::flushTransactionQueues() {
     // to prevent onHandleDestroyed from being called while the lock is held,
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
     std::vector<const TransactionState> transactions;
-    bool flushedATransaction = false;
     {
-        Mutex::Autolock _l(mStateLock);
-
-        auto it = mTransactionQueues.begin();
-        while (it != mTransactionQueues.end()) {
+        Mutex::Autolock _l(mQueueLock);
+        // Collect transactions from pending transaction queue.
+        auto it = mPendingTransactionQueues.begin();
+        while (it != mPendingTransactionQueues.end()) {
             auto& [applyToken, transactionQueue] = *it;
 
             while (!transactionQueue.empty()) {
@@ -3294,31 +3307,55 @@
                     break;
                 }
                 transactions.push_back(transaction);
-                applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
-                                      transaction.displays, transaction.flags,
-                                      mPendingInputWindowCommands, transaction.desiredPresentTime,
-                                      transaction.isAutoTimestamp, transaction.buffer,
-                                      transaction.postTime, transaction.privileged,
-                                      transaction.hasListenerCallbacks,
-                                      transaction.listenerCallbacks, transaction.originPid,
-                                      transaction.originUid, transaction.id, /*isMainThread*/ true);
                 transactionQueue.pop();
-                flushedATransaction = true;
             }
 
             if (transactionQueue.empty()) {
-                it = mTransactionQueues.erase(it);
-                mTransactionCV.broadcast();
+                it = mPendingTransactionQueues.erase(it);
+                mTransactionQueueCV.broadcast();
             } else {
                 it = std::next(it, 1);
             }
         }
+
+        // Collect transactions from current transaction queue or queue to pending transactions.
+        // Case 1: push to pending when transactionIsReadyToBeApplied is false.
+        // Case 2: push to pending when there exist a pending queue.
+        // Case 3: others are ready to apply.
+        while (!mTransactionQueue.empty()) {
+            const auto& transaction = mTransactionQueue.front();
+            bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
+                    mPendingTransactionQueues.end();
+            // Call transactionIsReadyToBeApplied first in case we need to
+            // incrementPendingBufferCount if the transaction contains a buffer.
+            if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp,
+                                               transaction.desiredPresentTime, transaction.states,
+                                               true) ||
+                pendingTransactions) {
+                mPendingTransactionQueues[transaction.applyToken].push(transaction);
+            } else {
+                transactions.push_back(transaction);
+            }
+            mTransactionQueue.pop();
+        }
     }
-    return flushedATransaction;
+
+    // Now apply all transactions.
+    Mutex::Autolock _l(mStateLock);
+    for (const auto& transaction : transactions) {
+        applyTransactionState(transaction.frameTimelineInfo, transaction.states,
+                              transaction.displays, transaction.flags,
+                              transaction.inputWindowCommands, transaction.desiredPresentTime,
+                              transaction.isAutoTimestamp, transaction.buffer, transaction.postTime,
+                              transaction.privileged, transaction.hasListenerCallbacks,
+                              transaction.listenerCallbacks, transaction.originPid,
+                              transaction.originUid, transaction.id);
+    }
 }
 
 bool SurfaceFlinger::transactionFlushNeeded() {
-    return !mTransactionQueues.empty();
+    Mutex::Autolock _l(mQueueLock);
+    return !mPendingTransactionQueues.empty();
 }
 
 bool SurfaceFlinger::transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t desiredPresentTime,
@@ -3339,8 +3376,10 @@
             continue;
         }
         if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
-          ready = false;
+            ready = false;
         }
+
+        Mutex::Autolock _l(mStateLock);
         sp<Layer> layer = nullptr;
         if (s.surface) {
             layer = fromHandleLocked(s.surface).promote();
@@ -3374,101 +3413,132 @@
 }
 
 status_t SurfaceFlinger::setTransactionState(
-        int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
+        const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
         const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
         const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
         bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
         const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
     ATRACE_CALL();
 
-    const int64_t postTime = systemTime();
+    {
+        Mutex::Autolock _l(mQueueLock);
 
-    bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
+        const int64_t postTime = systemTime();
+        bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
 
-    Mutex::Autolock _l(mStateLock);
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int originPid = ipc->getCallingPid();
+        const int originUid = ipc->getCallingUid();
 
-    // If its TransactionQueue already has a pending TransactionState or if it is pending
-    auto itr = mTransactionQueues.find(applyToken);
-    // if this is an animation frame, wait until prior animation frame has
-    // been applied by SF
-    if (flags & eAnimation) {
-        while (itr != mTransactionQueues.end()) {
-            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-            if (CC_UNLIKELY(err != NO_ERROR)) {
-                ALOGW_IF(err == TIMED_OUT,
-                         "setTransactionState timed out "
-                         "waiting for animation frame to apply");
-                break;
+        // If its TransactionQueue already has a pending TransactionState or if it is pending
+        auto itr = mPendingTransactionQueues.find(applyToken);
+        // if this is an animation frame, wait until prior animation frame has
+        // been applied by SF
+        if (flags & eAnimation) {
+            while (itr != mPendingTransactionQueues.end()) {
+                status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5));
+                if (CC_UNLIKELY(err != NO_ERROR)) {
+                    ALOGW_IF(err == TIMED_OUT,
+                             "setTransactionState timed out "
+                             "waiting for animation frame to apply");
+                    break;
+                }
+                itr = mPendingTransactionQueues.find(applyToken);
             }
-            itr = mTransactionQueues.find(applyToken);
         }
+
+        const bool pendingTransactions = itr != mPendingTransactionQueues.end();
+        // Expected present time is computed and cached on invalidate, so it may be stale.
+        if (!pendingTransactions) {
+            const auto now = systemTime();
+            const bool nextVsyncPending = now < mExpectedPresentTime.load();
+            const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
+            mExpectedPresentTime = calculateExpectedPresentTime(stats);
+            // The transaction might arrive just before the next vsync but after
+            // invalidate was called. In that case we need to get the next vsync
+            // afterwards.
+            if (nextVsyncPending) {
+                mExpectedPresentTime += stats.vsyncPeriod;
+            }
+        }
+
+        mTransactionQueue.emplace(frameTimelineInfo, states, displays, flags, applyToken,
+                                  inputWindowCommands, desiredPresentTime, isAutoTimestamp,
+                                  uncacheBuffer, postTime, privileged, hasListenerCallbacks,
+                                  listenerCallbacks, originPid, originUid, transactionId);
+
+        if (pendingTransactions ||
+            (!isAutoTimestamp && desiredPresentTime > mExpectedPresentTime.load())) {
+            setTransactionFlags(eTransactionFlushNeeded);
+            return NO_ERROR;
+        }
+
+        // TODO(b/159125966): Remove eEarlyWakeup completely as no client should use this flag
+        if (flags & eEarlyWakeup) {
+            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
+        }
+
+        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
+            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
+            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
+        }
+
+        const auto schedule = [](uint32_t flags) {
+            if (flags & eEarlyWakeup) return TransactionSchedule::Early;
+            if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+            if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+            return TransactionSchedule::Late;
+        }(flags);
+        setTransactionFlags(eTransactionFlushNeeded, schedule);
     }
 
-    const bool pendingTransactions = itr != mTransactionQueues.end();
-    // Expected present time is computed and cached on invalidate, so it may be stale.
-    if (!pendingTransactions) {
-        const auto now = systemTime();
-        const bool nextVsyncPending = now < mExpectedPresentTime.load();
-        const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
-        mExpectedPresentTime = calculateExpectedPresentTime(stats);
-        // The transaction might arrive just before the next vsync but after
-        // invalidate was called. In that case we need to get the next vsync
-        // afterwards.
-        if (nextVsyncPending) {
-            mExpectedPresentTime += stats.vsyncPeriod;
-        }
-    }
-
-    IPCThreadState* ipc = IPCThreadState::self();
-    const int originPid = ipc->getCallingPid();
-    const int originUid = ipc->getCallingUid();
-
-    // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
-    // if the transaction contains a buffer.
-    if (!transactionIsReadyToBeApplied(isAutoTimestamp, desiredPresentTime, states, true) ||
-        pendingTransactions) {
-        mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags,
-                                               desiredPresentTime, isAutoTimestamp, uncacheBuffer,
-                                               postTime, privileged, hasListenerCallbacks,
-                                               listenerCallbacks, originPid, originUid,
-                                               transactionId);
-        setTransactionFlags(eTransactionFlushNeeded);
+    // if this is a synchronous transaction, wait for it to take effect
+    // before returning.
+    const bool synchronous = flags & eSynchronous;
+    const bool syncInput = inputWindowCommands.syncInputWindows;
+    if (!synchronous && !syncInput) {
         return NO_ERROR;
     }
 
-    applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
-                          desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged,
-                          hasListenerCallbacks, listenerCallbacks, originPid, originUid,
-                          transactionId, /*isMainThread*/ false);
+    Mutex::Autolock _l(mStateLock);
+    if (synchronous) {
+        mTransactionPending = true;
+    }
+    if (syncInput) {
+        mPendingSyncInputWindows = true;
+    }
+
+    // applyTransactionState can be called by either the main SF thread or by
+    // another process through setTransactionState.  While a given process may wish
+    // to wait on synchronous transactions, the main SF thread should never
+    // be blocked.  Therefore, we only wait if isMainThread is false.
+    while (mTransactionPending || mPendingSyncInputWindows) {
+        status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+        if (CC_UNLIKELY(err != NO_ERROR)) {
+            // just in case something goes wrong in SF, return to the
+            // called after a few seconds.
+            ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+            mTransactionPending = false;
+            mPendingSyncInputWindows = false;
+            break;
+        }
+    }
+
     return NO_ERROR;
 }
 
-void SurfaceFlinger::applyTransactionState(
-        int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
-        const Vector<DisplayState>& displays, uint32_t flags,
-        const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
-        bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime,
-        bool privileged, bool hasListenerCallbacks,
-        const std::vector<ListenerCallbacks>& listenerCallbacks, int originPid, int originUid,
-        uint64_t transactionId, bool isMainThread) {
+void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+                                           const Vector<ComposerState>& states,
+                                           const Vector<DisplayState>& displays, uint32_t flags,
+                                           const InputWindowCommands& inputWindowCommands,
+                                           const int64_t desiredPresentTime, bool isAutoTimestamp,
+                                           const client_cache_t& uncacheBuffer,
+                                           const int64_t postTime, bool privileged,
+                                           bool hasListenerCallbacks,
+                                           const std::vector<ListenerCallbacks>& listenerCallbacks,
+                                           int originPid, int originUid, uint64_t transactionId) {
     uint32_t transactionFlags = 0;
 
-    if (flags & eAnimation) {
-        // For window updates that are part of an animation we must wait for
-        // previous animation "frames" to be handled.
-        while (!isMainThread && mAnimTransactionPending) {
-            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-            if (CC_UNLIKELY(err != NO_ERROR)) {
-                // just in case something goes wrong in SF, return to the
-                // caller after a few seconds.
-                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
-                        "waiting for previous animation frame");
-                mAnimTransactionPending = false;
-                break;
-            }
-        }
-    }
-
     for (const DisplayState& display : displays) {
         transactionFlags |= setDisplayStateLocked(display);
     }
@@ -3485,9 +3555,8 @@
     uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
         clientStateFlags |=
-                setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime,
-                                     isAutoTimestamp, postTime, privileged,
-                                     listenerCallbacksWithSurfaces, originPid, originUid);
+                setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp,
+                                     postTime, privileged, listenerCallbacksWithSurfaces);
         if ((flags & eAnimation) && state.state.surface) {
             if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
                 mScheduler->recordLayerHistory(layer.get(),
@@ -3527,80 +3596,25 @@
         transactionFlags = eTransactionNeeded;
     }
 
-    // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
-    // so we don't have to wake up again next frame to preform an uneeded traversal.
-    if (isMainThread && (transactionFlags & eTraversalNeeded)) {
-        transactionFlags = transactionFlags & (~eTraversalNeeded);
-        mForceTraversal = true;
-    }
-
-    const auto schedule = [](uint32_t flags) {
-        if (flags & eEarlyWakeup) return TransactionSchedule::Early;
-        if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
-        if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
-        return TransactionSchedule::Late;
-    }(flags);
-
     if (transactionFlags) {
         if (mInterceptor->isEnabled()) {
             mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
                                           originPid, originUid, transactionId);
         }
 
-        // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
-        if (flags & eEarlyWakeup) {
-            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
+        // We are on the main thread, we are about to preform a traversal. Clear the traversal bit
+        // so we don't have to wake up again next frame to preform an unnecessary traversal.
+        if (transactionFlags & eTraversalNeeded) {
+            transactionFlags = transactionFlags & (~eTraversalNeeded);
+            mForceTraversal = true;
         }
-
-        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
-            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
-            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
+        if (transactionFlags) {
+            setTransactionFlags(transactionFlags);
         }
 
-        // this triggers the transaction
-        setTransactionFlags(transactionFlags, schedule);
-
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
         }
-
-        // if this is a synchronous transaction, wait for it to take effect
-        // before returning.
-        const bool synchronous = flags & eSynchronous;
-        const bool syncInput = inputWindowCommands.syncInputWindows;
-        if (!synchronous && !syncInput) {
-            return;
-        }
-
-        if (synchronous) {
-            mTransactionPending = true;
-        }
-        if (syncInput) {
-            mPendingSyncInputWindows = true;
-        }
-
-
-        // applyTransactionState can be called by either the main SF thread or by
-        // another process through setTransactionState.  While a given process may wish
-        // to wait on synchronous transactions, the main SF thread should never
-        // be blocked.  Therefore, we only wait if isMainThread is false.
-        while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
-            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-            if (CC_UNLIKELY(err != NO_ERROR)) {
-                // just in case something goes wrong in SF, return to the
-                // called after a few seconds.
-                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
-                mTransactionPending = false;
-                mPendingSyncInputWindows = false;
-                break;
-            }
-        }
-    } else {
-        // Update VsyncModulator state machine even if transaction is not needed.
-        if (schedule == TransactionSchedule::EarlyStart ||
-            schedule == TransactionSchedule::EarlyEnd) {
-            modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
-        }
     }
 }
 
@@ -3665,10 +3679,9 @@
 }
 
 uint32_t SurfaceFlinger::setClientStateLocked(
-        int64_t frameTimelineVsyncId, const ComposerState& composerState,
+        const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
         int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged,
-        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks,
-        int originPid, int originUid) {
+        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
     const layer_state_t& s = composerState.state;
 
     for (auto& listener : s.listeners) {
@@ -3814,14 +3827,10 @@
         if (layer->setCornerRadius(s.cornerRadius))
             flags |= eTraversalNeeded;
     }
-
-    if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur &&
-        originalCallerCanUseBlurs(originPid, originUid)) {
+    if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
         if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
     }
-
-    if (what & layer_state_t::eBlurRegionsChanged &&
-        originalCallerCanUseBlurs(originPid, originUid)) {
+    if (what & layer_state_t::eBlurRegionsChanged) {
         if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eLayerStackChanged) {
@@ -3855,9 +3864,6 @@
             flags |= eTransactionNeeded|eTraversalNeeded;
         }
     }
-    if (what & layer_state_t::eDetachChildren) {
-        layer->detachChildren();
-    }
     if (what & layer_state_t::eTransformChanged) {
         if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
     }
@@ -3925,10 +3931,10 @@
             flags |= eTraversalNeeded;
         }
     }
-    if (what & layer_state_t::eFrameTimelineVsyncChanged) {
-        layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime);
-    } else if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
-        layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime);
+    if (what & layer_state_t::eFrameTimelineInfoChanged) {
+        layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime);
+    } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+        layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime);
     }
     if (what & layer_state_t::eFixedTransformHintChanged) {
         if (layer->setFixedTransformHint(s.fixedTransformHint)) {
@@ -3999,7 +4005,7 @@
 }
 
 uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
-    bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
+    bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);
     return hasChanges ? eTraversalNeeded : 0;
 }
 
@@ -4264,9 +4270,11 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr,
-                        mPendingInputWindowCommands, systemTime(), true, {}, false, {},
-                        0 /* Undefined transactionId */);
+
+    // It should be on the main thread, apply it directly.
+    applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands,
+                          systemTime(), true, {}, systemTime(), true, false, {}, getpid(), getuid(),
+                          0 /* Undefined transactionId */);
 
     setPowerModeInternal(display, hal::PowerMode::ON);
     const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -4843,15 +4851,12 @@
                   "  gpu_to_cpu_unsupported    : %d\n",
                   mTransactionFlags.load(), !mGpuToCpuSupported);
 
-    if (const auto displayId = getInternalDisplayIdLocked();
-        displayId && getHwComposer().isConnected(*displayId)) {
-        const auto activeConfig = getHwComposer().getActiveMode(*displayId);
+    if (const auto display = getDefaultDisplayDeviceLocked()) {
         std::string fps, xDpi, yDpi;
-        if (activeConfig) {
-            const auto vsyncPeriod = getHwComposer().getDisplayVsyncPeriod(*displayId);
-            fps = base::StringPrintf("%s", to_string(Fps::fromPeriodNsecs(vsyncPeriod)).c_str());
-            xDpi = base::StringPrintf("%.2f", activeConfig->getDpiX());
-            yDpi = base::StringPrintf("%.2f", activeConfig->getDpiY());
+        if (const auto activeMode = display->getActiveMode()) {
+            fps = to_string(activeMode->getFps());
+            xDpi = base::StringPrintf("%.2f", activeMode->getDpiX());
+            yDpi = base::StringPrintf("%.2f", activeMode->getDpiY());
         } else {
             fps = "unknown";
             xDpi = "unknown";
@@ -4909,23 +4914,24 @@
     result.append("\n");
 }
 
-void SurfaceFlinger::updateColorMatrixLocked() {
-    mat4 colorMatrix;
-    if (mGlobalSaturationFactor != 1.0f) {
-        // Rec.709 luma coefficients
-        float3 luminance{0.213f, 0.715f, 0.072f};
-        luminance *= 1.0f - mGlobalSaturationFactor;
-        mat4 saturationMatrix = mat4(
-            vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
-            vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
-            vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
-            vec4{0.0f, 0.0f, 0.0f, 1.0f}
-        );
-        colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer();
-    } else {
-        colorMatrix = mClientColorMatrix * mDaltonizer();
+mat4 SurfaceFlinger::calculateColorMatrix(float saturation) {
+    if (saturation == 1) {
+        return mat4();
     }
 
+    float3 luminance{0.213f, 0.715f, 0.072f};
+    luminance *= 1.0f - saturation;
+    mat4 saturationMatrix = mat4(vec4{luminance.r + saturation, luminance.r, luminance.r, 0.0f},
+                                 vec4{luminance.g, luminance.g + saturation, luminance.g, 0.0f},
+                                 vec4{luminance.b, luminance.b, luminance.b + saturation, 0.0f},
+                                 vec4{0.0f, 0.0f, 0.0f, 1.0f});
+    return saturationMatrix;
+}
+
+void SurfaceFlinger::updateColorMatrixLocked() {
+    mat4 colorMatrix =
+            mClientColorMatrix * calculateColorMatrix(mGlobalSaturationFactor) * mDaltonizer();
+
     if (mCurrentState.colorMatrix != colorMatrix) {
         mCurrentState.colorMatrix = colorMatrix;
         mCurrentState.colorMatrixChanged = true;
@@ -5015,7 +5021,7 @@
         case CAPTURE_LAYERS:
         case CAPTURE_DISPLAY:
         case SET_DISPLAY_BRIGHTNESS:
-        case SET_FRAME_TIMELINE_VSYNC:
+        case SET_FRAME_TIMELINE_INFO:
         // This is not sensitive information, so should not require permission control.
         case GET_GPU_CONTEXT_PRIORITY: {
             return OK;
@@ -5637,7 +5643,8 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, args.allowProtected, captureListener);
+                               args.pixelFormat, args.allowProtected, args.grayscale,
+                               captureListener);
 }
 
 status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
@@ -5673,7 +5680,7 @@
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
                                ui::PixelFormat::RGBA_8888, false /* allowProtected */,
-                               captureListener);
+                               false /* grayscale */, captureListener);
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -5719,12 +5726,12 @@
             crop.bottom = parentSourceBounds.getHeight();
         }
 
-        if (crop.isEmpty() || args.frameScale <= 0.0f) {
+        if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) {
             // Error out if the layer has no source bounds (i.e. they are boundless) and a source
             // crop was not specified, or an invalid frame scale was provided.
             return BAD_VALUE;
         }
-        reqSize = ui::Size(crop.width() * args.frameScale, crop.height() * args.frameScale);
+        reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY);
 
         for (const auto& handle : args.excludeHandles) {
             sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
@@ -5794,13 +5801,14 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, args.allowProtected, captureListener);
+                               args.pixelFormat, args.allowProtected, args.grayscale,
+                               captureListener);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
                                              ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
-                                             const bool allowProtected,
+                                             bool allowProtected, bool grayscale,
                                              const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
@@ -5831,12 +5839,13 @@
                                              static_cast<android_pixel_format>(reqPixelFormat),
                                              1 /* layerCount */, usage, "screenshot");
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
-                               false /* regionSampling */, captureListener);
+                               false /* regionSampling */, grayscale, captureListener);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
-                                             sp<GraphicBuffer>& buffer, const bool regionSampling,
+                                             sp<GraphicBuffer>& buffer, bool regionSampling,
+                                             bool grayscale,
                                              const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
@@ -5852,7 +5861,7 @@
         if (mRefreshPending) {
             ALOGW("Skipping screenshot for now");
             captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling,
-                                captureListener);
+                                grayscale, captureListener);
             return;
         }
         ScreenCaptureResults captureResults;
@@ -5867,7 +5876,7 @@
         status_t result = NO_ERROR;
         renderArea->render([&] {
             result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem,
-                                            regionSampling, captureResults);
+                                            regionSampling, grayscale, captureResults);
         });
 
         captureResults.result = result;
@@ -5880,7 +5889,7 @@
 status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
                                                 TraverseLayersFunction traverseLayers,
                                                 const sp<GraphicBuffer>& buffer, bool forSystem,
-                                                bool regionSampling,
+                                                bool regionSampling, bool grayscale,
                                                 ScreenCaptureResults& captureResults) {
     ATRACE_CALL();
 
@@ -5921,6 +5930,9 @@
     clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
     clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
 
+    const float colorSaturation = grayscale ? 0 : 1;
+    clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation);
+
     const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
 
     compositionengine::LayerFE::LayerSettings fillLayer;
@@ -6383,21 +6395,21 @@
     }));
 }
 
-status_t SurfaceFlinger::setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
-                                               int64_t frameTimelineVsyncId) {
+status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
+                                              const FrameTimelineInfo& frameTimelineInfo) {
     Mutex::Autolock lock(mStateLock);
     if (!authenticateSurfaceTextureLocked(surface)) {
-        ALOGE("Attempt to set frame timeline vsync on an unrecognized IGraphicBufferProducer");
+        ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer");
         return BAD_VALUE;
     }
 
     sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
     if (layer == nullptr) {
-        ALOGE("Attempt to set frame timeline vsync on a layer that no longer exists");
+        ALOGE("Attempt to set frame timeline info on a layer that no longer exists");
         return BAD_VALUE;
     }
 
-    layer->setFrameTimelineVsyncForBuffer(frameTimelineVsyncId);
+    layer->setFrameTimelineInfoForBuffer(frameTimelineInfo);
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e82095b..66fc4f0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -343,10 +343,10 @@
     virtual ~SurfaceFlinger();
 
     virtual uint32_t setClientStateLocked(
-            int64_t frameTimelineVsyncId, const ComposerState& composerState,
+            const FrameTimelineInfo& info, const ComposerState& composerState,
             int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged,
-            std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks,
-            int originPid, int originUid) REQUIRES(mStateLock);
+            std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
+            REQUIRES(mStateLock);
     virtual void commitTransactionLocked();
 
     // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
@@ -435,17 +435,21 @@
     };
 
     struct TransactionState {
-        TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates,
+        TransactionState(const FrameTimelineInfo& frameTimelineInfo,
+                         const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime, bool isAutoTimestamp,
-                         const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged,
-                         bool hasListenerCallbacks,
+                         const sp<IBinder>& applyToken,
+                         const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+                         bool isAutoTimestamp, const client_cache_t& uncacheBuffer,
+                         int64_t postTime, bool privileged, bool hasListenerCallbacks,
                          std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
                          int originUid, uint64_t transactionId)
-              : frameTimelineVsyncId(frameTimelineVsyncId),
+              : frameTimelineInfo(frameTimelineInfo),
                 states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
+                applyToken(applyToken),
+                inputWindowCommands(inputWindowCommands),
                 desiredPresentTime(desiredPresentTime),
                 isAutoTimestamp(isAutoTimestamp),
                 buffer(uncacheBuffer),
@@ -457,10 +461,12 @@
                 originUid(originUid),
                 id(transactionId) {}
 
-        int64_t frameTimelineVsyncId;
+        FrameTimelineInfo frameTimelineInfo;
         Vector<ComposerState> states;
         Vector<DisplayState> displays;
         uint32_t flags;
+        sp<IBinder> applyToken;
+        InputWindowCommands inputWindowCommands;
         const int64_t desiredPresentTime;
         const bool isAutoTimestamp;
         client_cache_t buffer;
@@ -522,7 +528,8 @@
     void destroyDisplay(const sp<IBinder>& displayToken) override;
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
-    status_t setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
+    status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+                                 const Vector<ComposerState>& state,
                                  const Vector<DisplayState>& displays, uint32_t flags,
                                  const sp<IBinder>& applyToken,
                                  const InputWindowCommands& inputWindowCommands,
@@ -608,8 +615,8 @@
                           int8_t compatibility, bool shouldBeSeamless) override;
     status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override;
 
-    status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
-                                   int64_t frameTimelineVsyncId) override;
+    status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
+                                  const FrameTimelineInfo& frameTimelineInfo) override;
 
     status_t addTransactionTraceListener(
             const sp<gui::ITransactionTraceListener>& listener) override;
@@ -727,17 +734,17 @@
     /*
      * Transactions
      */
-    void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
+    void applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
                                const int64_t desiredPresentTime, bool isAutoTimestamp,
                                const client_cache_t& uncacheBuffer, const int64_t postTime,
                                bool privileged, bool hasListenerCallbacks,
                                const std::vector<ListenerCallbacks>& listenerCallbacks,
-                               int originPid, int originUid, uint64_t transactionId,
-                               bool isMainThread = false) REQUIRES(mStateLock);
-    // Returns true if at least one transaction was flushed
-    bool flushTransactionQueues();
+                               int originPid, int originUid, uint64_t transactionId)
+            REQUIRES(mStateLock);
+    // flush pending transaction that was presented after desiredPresentTime.
+    void flushTransactionQueues();
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
     uint32_t getTransactionFlags(uint32_t flags);
@@ -755,7 +762,7 @@
     void commitOffscreenLayers();
     bool transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states,
-                                       bool updateTransactionCounters = false) REQUIRES(mStateLock);
+                                       bool updateTransactionCounters = false);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
             REQUIRES(mStateLock);
@@ -810,13 +817,14 @@
     void startBootAnim();
 
     status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
-                                 ui::PixelFormat, const bool allowProtected,
+                                 ui::PixelFormat, bool allowProtected, bool grayscale,
                                  const sp<IScreenCaptureListener>&);
     status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
-                                 bool regionSampling, const sp<IScreenCaptureListener>&);
+                                 bool regionSampling, bool grayscale,
+                                 const sp<IScreenCaptureListener>&);
     status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
                                     const sp<GraphicBuffer>&, bool forSystem, bool regionSampling,
-                                    ScreenCaptureResults&);
+                                    bool grayscale, ScreenCaptureResults&);
 
     sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
     sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
@@ -894,6 +902,7 @@
     /*
      * Display management
      */
+    DisplayModes loadSupportedDisplayModes(PhysicalDisplayId) const;
     sp<DisplayDevice> setupNewDisplayDeviceInternal(
             const wp<IBinder>& displayToken,
             std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -1019,6 +1028,8 @@
 
     void onFrameRateFlexibilityTokenReleased();
 
+    static mat4 calculateColorMatrix(float saturation);
+
     void updateColorMatrixLocked();
 
     // Verify that transaction is being called by an approved process:
@@ -1172,8 +1183,11 @@
     uint32_t mTexturePoolSize = 0;
     std::vector<uint32_t> mTexturePool;
 
-    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
-
+    mutable Mutex mQueueLock;
+    Condition mTransactionQueueCV;
+    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
+            mPendingTransactionQueues GUARDED_BY(mQueueLock);
+    std::queue<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
     /*
      * Feature prototyping
      */
@@ -1251,7 +1265,6 @@
     const float mEmulatedDisplayDensity;
 
     sp<os::IInputFlinger> mInputFlinger;
-    InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
     // Should only be accessed by the main thread.
     InputWindowCommands mInputWindowCommands;
 
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 3548923..61005c9 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -150,7 +150,6 @@
                    layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque |
                            layer_state_t::eLayerSecure);
     addReparentLocked(transaction, layerId, getLayerIdFromWeakRef(layer->mCurrentParent));
-    addDetachChildrenLocked(transaction, layerId, layer->isLayerDetached());
     addRelativeParentLocked(transaction, layerId,
                             getLayerIdFromWeakRef(layer->mCurrentState.zOrderRelativeOf),
                             layer->mCurrentState.z);
@@ -409,13 +408,6 @@
     overrideChange->set_parent_id(parentId);
 }
 
-void SurfaceInterceptor::addDetachChildrenLocked(Transaction* transaction, int32_t layerId,
-                                                 bool detached) {
-    SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
-    DetachChildrenChange* overrideChange(change->mutable_detach_children());
-    overrideChange->set_detach_children(detached);
-}
-
 void SurfaceInterceptor::addRelativeParentLocked(Transaction* transaction, int32_t layerId,
                                                  int32_t parentId, int z) {
     SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
@@ -498,9 +490,6 @@
         addReparentChildrenLocked(transaction, layerId,
                                   getLayerIdFromHandle(state.reparentSurfaceControl->getHandle()));
     }
-    if (state.what & layer_state_t::eDetachChildren) {
-        addDetachChildrenLocked(transaction, layerId, true);
-    }
     if (state.what & layer_state_t::eRelativeLayerChanged) {
         addRelativeParentLocked(transaction, layerId,
                                 getLayerIdFromHandle(
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 3df79c6..3e27e83 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -177,7 +177,6 @@
                               uint64_t transactionId);
     void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
     void addReparentChildrenLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
-    void addDetachChildrenLocked(Transaction* transaction, int32_t layerId, bool detached);
     void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId,
                                  int z);
     void addShadowRadiusLocked(Transaction* transaction, int32_t layerId, float shadowRadius);
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index e8b24b4..cfaf229 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -21,7 +21,6 @@
         "CommonTypes_test.cpp",
         "Credentials_test.cpp",
         "DereferenceSurfaceControl_test.cpp",
-        "DetachChildren_test.cpp",
         "DisplayConfigs_test.cpp",
         "EffectLayer_test.cpp",
         "InvalidHandles_test.cpp",
diff --git a/services/surfaceflinger/tests/DetachChildren_test.cpp b/services/surfaceflinger/tests/DetachChildren_test.cpp
deleted file mode 100644
index abf8b1a..0000000
--- a/services/surfaceflinger/tests/DetachChildren_test.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * 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 clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#include "LayerTransactionTest.h"
-
-namespace android {
-
-class DetachChildren : public LayerTransactionTest {
-protected:
-    virtual void SetUp() {
-        LayerTransactionTest::SetUp();
-
-        mMainSurface = createLayer(String8("Main Test Surface"), mMainSurfaceBounds.width(),
-                                   mMainSurfaceBounds.height(), 0, mBlackBgSurface.get());
-
-        ASSERT_TRUE(mMainSurface != nullptr);
-        ASSERT_TRUE(mMainSurface->isValid());
-
-        TransactionUtils::fillSurfaceRGBA8(mMainSurface, mMainSurfaceColor);
-
-        asTransaction([&](Transaction& t) {
-            t.setLayer(mMainSurface, INT32_MAX - 1)
-                    .setPosition(mMainSurface, mMainSurfaceBounds.left, mMainSurfaceBounds.top)
-                    .show(mMainSurface);
-        });
-    }
-
-    virtual void TearDown() {
-        LayerTransactionTest::TearDown();
-        mMainSurface = 0;
-    }
-
-    sp<SurfaceControl> mMainSurface;
-    Color mMainSurfaceColor = {195, 63, 63, 255};
-    Rect mMainSurfaceBounds = Rect(64, 64, 128, 128);
-    std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(DetachChildren, RelativesAreNotDetached) {
-    Color relativeColor = {10, 10, 10, 255};
-    Rect relBounds = Rect(64, 64, 74, 74);
-
-    sp<SurfaceControl> relative =
-            createLayer(String8("relativeTestSurface"), relBounds.width(), relBounds.height(), 0);
-    TransactionUtils::fillSurfaceRGBA8(relative, relativeColor);
-
-    Transaction{}
-            .setRelativeLayer(relative, mMainSurface, 1)
-            .setPosition(relative, relBounds.left, relBounds.top)
-            .apply();
-
-    {
-        // The relative should be on top of the FG control.
-        mCapture = screenshot();
-        mCapture->expectColor(relBounds, relativeColor);
-    }
-    Transaction{}.detachChildren(mMainSurface).apply();
-
-    {
-        // Nothing should change at this point.
-        mCapture = screenshot();
-        mCapture->expectColor(relBounds, relativeColor);
-    }
-
-    Transaction{}.hide(relative).apply();
-
-    {
-        // Ensure that the relative was actually hidden, rather than
-        // being left in the detached but visible state.
-        mCapture = screenshot();
-        mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor);
-    }
-}
-
-TEST_F(DetachChildren, DetachChildrenSameClient) {
-    Color childColor = {200, 200, 200, 255};
-    Rect childBounds = Rect(74, 74, 84, 84);
-    sp<SurfaceControl> child = createLayer(String8("Child surface"), childBounds.width(),
-                                           childBounds.height(), 0, mMainSurface.get());
-    ASSERT_TRUE(child->isValid());
-
-    TransactionUtils::fillSurfaceRGBA8(child, childColor);
-
-    asTransaction([&](Transaction& t) {
-        t.show(child);
-        t.setPosition(child, childBounds.left - mMainSurfaceBounds.left,
-                      childBounds.top - mMainSurfaceBounds.top);
-    });
-
-    {
-        mCapture = screenshot();
-        // Expect main color around the child surface
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-
-    asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); });
-
-    asTransaction([&](Transaction& t) { t.hide(child); });
-
-    // Since the child has the same client as the parent, it will not get
-    // detached and will be hidden.
-    {
-        mCapture = screenshot();
-        mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor);
-    }
-}
-
-TEST_F(DetachChildren, DetachChildrenDifferentClient) {
-    Color childColor = {200, 200, 200, 255};
-    Rect childBounds = Rect(74, 74, 84, 84);
-
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
-                          childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
-    ASSERT_TRUE(childNewClient->isValid());
-
-    TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
-
-    asTransaction([&](Transaction& t) {
-        t.show(childNewClient);
-        t.setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
-                      childBounds.top - mMainSurfaceBounds.top);
-    });
-
-    {
-        mCapture = screenshot();
-        // Expect main color around the child surface
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-
-    asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); });
-
-    asTransaction([&](Transaction& t) { t.hide(childNewClient); });
-
-    // Nothing should have changed.
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-}
-
-TEST_F(DetachChildren, DetachChildrenThenAttach) {
-    Color childColor = {200, 200, 200, 255};
-    Rect childBounds = Rect(74, 74, 84, 84);
-
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
-                          childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
-    ASSERT_TRUE(childNewClient->isValid());
-
-    TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
-
-    Transaction()
-            .show(childNewClient)
-            .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
-                         childBounds.top - mMainSurfaceBounds.top)
-            .apply();
-
-    {
-        mCapture = screenshot();
-        // Expect main color around the child surface
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-
-    Transaction().detachChildren(mMainSurface).apply();
-    Transaction().hide(childNewClient).apply();
-
-    // Nothing should have changed.
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-
-    Color newParentColor = Color::RED;
-    Rect newParentBounds = Rect(20, 20, 52, 52);
-    sp<SurfaceControl> newParentSurface =
-            createLayer(String8("New Parent Surface"), newParentBounds.width(),
-                        newParentBounds.height(), 0);
-    TransactionUtils::fillSurfaceRGBA8(newParentSurface, newParentColor);
-    Transaction()
-            .setLayer(newParentSurface, INT32_MAX - 1)
-            .show(newParentSurface)
-            .setPosition(newParentSurface, newParentBounds.left, newParentBounds.top)
-            .reparent(childNewClient, newParentSurface)
-            .apply();
-    {
-        mCapture = screenshot();
-        // Child is now hidden.
-        mCapture->expectColor(newParentBounds, newParentColor);
-    }
-}
-
-TEST_F(DetachChildren, DetachChildrenWithDeferredTransaction) {
-    Color childColor = {200, 200, 200, 255};
-    Rect childBounds = Rect(74, 74, 84, 84);
-
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
-                          childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
-    ASSERT_TRUE(childNewClient->isValid());
-
-    TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
-
-    Transaction()
-            .show(childNewClient)
-            .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
-                         childBounds.top - mMainSurfaceBounds.top)
-            .apply();
-
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-
-    Transaction()
-            .deferTransactionUntil_legacy(childNewClient, mMainSurface,
-                                          mMainSurface->getSurface()->getNextFrameNumber())
-            .apply();
-    Transaction().detachChildren(mMainSurface).apply();
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mMainSurface, Color::RED,
-                                                      mMainSurfaceBounds.width(),
-                                                      mMainSurfaceBounds.height()));
-
-    // BufferLayer can still dequeue buffers even though there's a detached layer with a
-    // deferred transaction.
-    {
-        SCOPED_TRACE("new buffer");
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, Color::RED);
-        mCapture->expectColor(childBounds, childColor);
-    }
-}
-
-/**
- * Tests that a deferring transaction on an already detached layer will be dropped gracefully and
- * allow the barrier layer to dequeue buffers.
- *
- * Fixes b/150924737 - buffer cannot be latched because it waits for a detached layer
- * to commit its pending states.
- */
-TEST_F(DetachChildren, DeferredTransactionOnDetachedChildren) {
-    Color childColor = {200, 200, 200, 255};
-    Rect childBounds = Rect(74, 74, 84, 84);
-
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
-                          childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
-    ASSERT_TRUE(childNewClient->isValid());
-
-    TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
-
-    Transaction()
-            .show(childNewClient)
-            .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
-                         childBounds.top - mMainSurfaceBounds.top)
-            .apply();
-
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectColor(childBounds, childColor);
-    }
-
-    Transaction().detachChildren(mMainSurface).apply();
-    Transaction()
-            .setCrop_legacy(childNewClient, {0, 0, childBounds.width(), childBounds.height()})
-            .deferTransactionUntil_legacy(childNewClient, mMainSurface,
-                                          mMainSurface->getSurface()->getNextFrameNumber())
-            .apply();
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mMainSurface, Color::RED,
-                                                      mMainSurfaceBounds.width(),
-                                                      mMainSurfaceBounds.height()));
-
-    // BufferLayer can still dequeue buffers even though there's a detached layer with a
-    // deferred transaction.
-    {
-        SCOPED_TRACE("new buffer");
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, Color::RED);
-        mCapture->expectColor(childBounds, childColor);
-    }
-}
-
-TEST_F(DetachChildren, ReparentParentLayerOfDetachedChildren) {
-    Color childColor = {200, 200, 200, 255};
-    Rect childBounds = Rect(74, 74, 94, 94);
-    Color grandchildColor = Color::RED;
-    Rect grandchildBounds = Rect(80, 80, 90, 90);
-
-    sp<SurfaceComposerClient> newClient1 = new SurfaceComposerClient;
-    sp<SurfaceComposerClient> newClient2 = new SurfaceComposerClient;
-
-    sp<SurfaceControl> childSurface =
-            createSurface(newClient1, "Child surface", childBounds.width(), childBounds.height(),
-                          PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
-    sp<SurfaceControl> grandchildSurface =
-            createSurface(newClient2, "Grandchild Surface", grandchildBounds.width(),
-                          grandchildBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, childSurface.get());
-
-    TransactionUtils::fillSurfaceRGBA8(childSurface, childColor);
-    TransactionUtils::fillSurfaceRGBA8(grandchildSurface, grandchildColor);
-
-    Transaction()
-            .show(childSurface)
-            .show(grandchildSurface)
-            .setPosition(childSurface, childBounds.left - mMainSurfaceBounds.left,
-                         childBounds.top - mMainSurfaceBounds.top)
-            .setPosition(grandchildSurface, grandchildBounds.left - childBounds.left,
-                         grandchildBounds.top - childBounds.top)
-            .apply();
-
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectBorder(grandchildBounds, childColor);
-        mCapture->expectColor(grandchildBounds, grandchildColor);
-    }
-
-    Transaction().detachChildren(childSurface).apply();
-
-    // Remove main surface offscreen
-    Transaction().reparent(mMainSurface, nullptr).apply();
-    {
-        mCapture = screenshot();
-        mCapture->expectColor(mMainSurfaceBounds, Color::BLACK);
-    }
-
-    Transaction().reparent(mMainSurface, mBlackBgSurface).apply();
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectBorder(grandchildBounds, childColor);
-        mCapture->expectColor(grandchildBounds, grandchildColor);
-    }
-
-    Transaction().hide(grandchildSurface).apply();
-
-    // grandchild is still detached so it will not hide
-    {
-        mCapture = screenshot();
-        mCapture->expectBorder(childBounds, mMainSurfaceColor);
-        mCapture->expectBorder(grandchildBounds, childColor);
-        mCapture->expectColor(grandchildBounds, grandchildColor);
-    }
-}
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index 93d5f2f..f010786 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -30,12 +30,14 @@
     DisplayCaptureArgs args;
     args.pixelFormat = ui::PixelFormat::RGB_565;
     args.sourceCrop = Rect(0, 0, 500, 200);
-    args.frameScale = 2;
+    args.frameScaleX = 2;
+    args.frameScaleY = 4;
     args.captureSecureLayers = true;
     args.displayToken = new BBinder();
     args.width = 10;
     args.height = 20;
     args.useIdentityTransform = true;
+    args.grayscale = true;
 
     Parcel p;
     args.write(p);
@@ -46,23 +48,27 @@
 
     ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
     ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
-    ASSERT_EQ(args.frameScale, args2.frameScale);
+    ASSERT_EQ(args.frameScaleX, args2.frameScaleX);
+    ASSERT_EQ(args.frameScaleY, args2.frameScaleY);
     ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers);
     ASSERT_EQ(args.displayToken, args2.displayToken);
     ASSERT_EQ(args.width, args2.width);
     ASSERT_EQ(args.height, args2.height);
     ASSERT_EQ(args.useIdentityTransform, args2.useIdentityTransform);
+    ASSERT_EQ(args.grayscale, args2.grayscale);
 }
 
 TEST(LayerStateTest, ParcellingLayerCaptureArgs) {
     LayerCaptureArgs args;
     args.pixelFormat = ui::PixelFormat::RGB_565;
     args.sourceCrop = Rect(0, 0, 500, 200);
-    args.frameScale = 2;
+    args.frameScaleX = 2;
+    args.frameScaleY = 4;
     args.captureSecureLayers = true;
     args.layerHandle = new BBinder();
     args.excludeHandles = {new BBinder(), new BBinder()};
     args.childrenOnly = false;
+    args.grayscale = true;
 
     Parcel p;
     args.write(p);
@@ -73,11 +79,13 @@
 
     ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
     ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
-    ASSERT_EQ(args.frameScale, args2.frameScale);
+    ASSERT_EQ(args.frameScaleX, args2.frameScaleX);
+    ASSERT_EQ(args.frameScaleY, args2.frameScaleY);
     ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers);
     ASSERT_EQ(args.layerHandle, args2.layerHandle);
     ASSERT_EQ(args.excludeHandles, args2.excludeHandles);
     ASSERT_EQ(args.childrenOnly, args2.childrenOnly);
+    ASSERT_EQ(args.grayscale, args2.grayscale);
 }
 
 TEST(LayerStateTest, ParcellingScreenCaptureResults) {
@@ -106,5 +114,34 @@
     ASSERT_EQ(results.result, results2.result);
 }
 
+/**
+ * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled
+ * matches the object that's unparceled.
+ */
+TEST(LayerStateTest, ParcelUnparcelLayerStateT) {
+    layer_state_t input;
+    input.frameTimelineInfo.vsyncId = 1;
+    input.frameTimelineInfo.inputEventId = 2;
+    Parcel p;
+    input.write(p);
+    layer_state_t output;
+    p.setDataPosition(0);
+    output.read(p);
+    ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId);
+    ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId);
+}
+
+TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) {
+    layer_state_t layer1;
+    layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
+    layer_state_t layer2;
+    layer2.frameTimelineInfo.inputEventId = 1;
+    layer2.what |= layer_state_t::eFrameTimelineInfoChanged;
+
+    layer1.merge(layer2);
+
+    ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId);
+}
+
 } // namespace test
 } // namespace android
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 214a0cd..51ce1d3 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -487,7 +487,9 @@
     // red area to the right of the blue area
     mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
 
-    captureArgs.frameScale = 0.5f;
+    captureArgs.frameScaleX = 0.5f;
+    captureArgs.frameScaleY = 0.5f;
+
     ScreenCapture::captureLayers(&mCapture, captureArgs);
     // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
     mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
@@ -768,6 +770,41 @@
     mCapture->expectBorder(Rect(128, 128, 160, 160), {63, 63, 195, 255});
 }
 
+TEST_F(ScreenCaptureTest, CaptureWithGrayscale) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+                                                ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                mBGSurfaceControl.get()));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+    Transaction().show(layer).setLayer(layer, INT32_MAX).apply();
+
+    LayerCaptureArgs captureArgs;
+    captureArgs.layerHandle = layer->getHandle();
+
+    ScreenCapture::captureLayers(&mCapture, captureArgs);
+    mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
+
+    captureArgs.grayscale = true;
+
+    const uint8_t tolerance = 1;
+
+    // Values based on SurfaceFlinger::calculateColorMatrix
+    float3 luminance{0.213f, 0.715f, 0.072f};
+
+    ScreenCapture::captureLayers(&mCapture, captureArgs);
+
+    uint8_t expectedColor = luminance.r * 255;
+    mCapture->expectColor(Rect(0, 0, 32, 32),
+                          Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
+    ScreenCapture::captureLayers(&mCapture, captureArgs);
+
+    expectedColor = luminance.b * 255;
+    mCapture->expectColor(Rect(0, 0, 32, 32),
+                          Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);
+}
+
 // In the following tests we verify successful skipping of a parent layer,
 // so we use the same verification logic and only change how we mutate
 // the parent layer to verify that various properties are ignored.
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8dc9a12..fa88ca5 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -194,7 +194,6 @@
     bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
     bool reparentUpdateFound(const SurfaceChange& change, bool found);
     bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
-    bool detachChildrenUpdateFound(const SurfaceChange& change, bool found);
     bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found);
     bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found);
     bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
@@ -232,7 +231,6 @@
     void deferredTransactionUpdate(Transaction&);
     void reparentUpdate(Transaction&);
     void relativeParentUpdate(Transaction&);
-    void detachChildrenUpdate(Transaction&);
     void reparentChildrenUpdate(Transaction&);
     void shadowRadiusUpdate(Transaction&);
     void surfaceCreation(Transaction&);
@@ -412,10 +410,6 @@
     t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl, RELATIVE_Z);
 }
 
-void SurfaceInterceptorTest::detachChildrenUpdate(Transaction& t) {
-    t.detachChildren(mBGSurfaceControl);
-}
-
 void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) {
     t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl);
 }
@@ -452,7 +446,6 @@
     runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
     runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
     runInTransaction(&SurfaceInterceptorTest::reparentChildrenUpdate);
-    runInTransaction(&SurfaceInterceptorTest::detachChildrenUpdate);
     runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
     runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate);
 }
@@ -667,16 +660,6 @@
     return found;
 }
 
-bool SurfaceInterceptorTest::detachChildrenUpdateFound(const SurfaceChange& change, bool found) {
-    bool detachChildren(change.detach_children().detach_children());
-    if (detachChildren && !found) {
-        found = true;
-    } else if (detachChildren && found) {
-        []() { FAIL(); }();
-    }
-    return found;
-}
-
 bool SurfaceInterceptorTest::reparentChildrenUpdateFound(const SurfaceChange& change, bool found) {
     bool hasId(change.reparent_children().parent_id() == mFGLayerId);
     if (hasId && !found) {
@@ -761,9 +744,6 @@
                         case SurfaceChange::SurfaceChangeCase::kRelativeParent:
                             foundUpdate = relativeParentUpdateFound(change, foundUpdate);
                             break;
-                        case SurfaceChange::SurfaceChangeCase::kDetachChildren:
-                            foundUpdate = detachChildrenUpdateFound(change, foundUpdate);
-                            break;
                         case SurfaceChange::SurfaceChangeCase::kShadowRadius:
                             foundUpdate = shadowRadiusUpdateFound(change, foundUpdate);
                             break;
@@ -793,7 +773,6 @@
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparentChildren));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent));
-    ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDetachChildren));
 }
 
 bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
@@ -968,11 +947,6 @@
                 SurfaceChange::SurfaceChangeCase::kRelativeParent);
 }
 
-TEST_F(SurfaceInterceptorTest, InterceptDetachChildrenUpdateWorks) {
-    captureTest(&SurfaceInterceptorTest::detachChildrenUpdate,
-                SurfaceChange::SurfaceChangeCase::kDetachChildren);
-}
-
 TEST_F(SurfaceInterceptorTest, InterceptShadowRadiusUpdateWorks) {
     captureTest(&SurfaceInterceptorTest::shadowRadiusUpdate,
                 SurfaceChange::SurfaceChangeCase::kShadowRadius);
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index a361b1e..33823d7 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -57,6 +57,8 @@
                                                       // Sample usage bits from screenrecord
                                                       GRALLOC_USAGE_HW_VIDEO_ENCODER |
                                                               GRALLOC_USAGE_SW_READ_OFTEN);
+                sp<BufferListener> listener = new BufferListener(this);
+                itemConsumer->setFrameAvailableListener(listener);
 
                 vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
                                                                 false /*secure*/);
@@ -68,6 +70,13 @@
                                        Rect(displayState.layerStackSpaceRect), Rect(resolution));
                 t.apply();
                 SurfaceComposerClient::Transaction().apply(true);
+
+                std::unique_lock lock(mMutex);
+                mAvailable = false;
+                // Wait for frame buffer ready.
+                mCondition.wait_for(lock, std::chrono::seconds(2),
+                                    [this]() NO_THREAD_SAFETY_ANALYSIS { return mAvailable; });
+
                 BufferItem item;
                 itemConsumer->acquireBuffer(&item, 0, true);
                 auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
@@ -80,6 +89,23 @@
 protected:
     LayerTransactionTest* mDelegate;
     RenderPath mRenderPath;
+    std::mutex mMutex;
+    std::condition_variable mCondition;
+    bool mAvailable = false;
+
+    void onFrameAvailable() {
+        std::unique_lock lock(mMutex);
+        mAvailable = true;
+        mCondition.notify_all();
+    }
+
+    class BufferListener : public ConsumerBase::FrameAvailableListener {
+    public:
+        BufferListener(LayerRenderPathTestHarness* owner) : mOwner(owner) {}
+        LayerRenderPathTestHarness* mOwner;
+
+        void onFrameAvailable(const BufferItem& /*item*/) { mOwner->onFrameAvailable(); }
+    };
 };
 
 class LayerTypeTransactionHarness : public LayerTransactionTest {
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index bd49728..efa15f1 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -63,9 +63,7 @@
 
 // Mock test helpers
 using ::testing::_;
-using ::testing::AtLeast;
 using ::testing::DoAll;
-using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
@@ -74,9 +72,11 @@
 using Display = V2_1::Display;
 
 ///////////////////////////////////////////////
-
-constexpr PhysicalDisplayId kPrimaryDisplayId = PhysicalDisplayId::fromPort(PRIMARY_DISPLAY);
-constexpr PhysicalDisplayId kExternalDisplayId = PhysicalDisplayId::fromPort(EXTERNAL_DISPLAY);
+constexpr PhysicalDisplayId physicalIdFromHwcDisplayId(Display hwcId) {
+    return PhysicalDisplayId::fromPort(hwcId);
+}
+constexpr PhysicalDisplayId kPrimaryDisplayId = physicalIdFromHwcDisplayId(PRIMARY_DISPLAY);
+constexpr PhysicalDisplayId kExternalDisplayId = physicalIdFromHwcDisplayId(EXTERNAL_DISPLAY);
 
 struct TestColor {
 public:
@@ -158,7 +158,7 @@
                 self->mReceivedDisplayEvents.push_back(buffer[i]);
             }
         }
-        ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
+        ALOGD_IF(n < 0, "Error reading events (%s)", strerror(-n));
         return 1;
     }
 
@@ -174,7 +174,7 @@
     void setExpectationsForConfigs(Display display, std::vector<TestConfig> testConfigs,
                                    Config activeConfig, V2_4::VsyncPeriodNanos defaultVsyncPeriod) {
         std::vector<Config> configIds;
-        for (int i = 0; i < testConfigs.size(); i++) {
+        for (size_t i = 0; i < testConfigs.size(); i++) {
             configIds.push_back(testConfigs[i].id);
 
             EXPECT_CALL(*mMockComposer,
@@ -269,10 +269,10 @@
         mMockComposer = nullptr;
     }
 
-    void waitForDisplayTransaction() {
+    void waitForDisplayTransaction(Display display) {
         // Both a refresh and a vsync event are needed to apply pending display
         // transactions.
-        mFakeComposerClient->refreshDisplay(EXTERNAL_DISPLAY);
+        mFakeComposerClient->refreshDisplay(display);
         mFakeComposerClient->runVSyncAndWait();
 
         // Extra vsync and wait to avoid a 10% flake due to a race.
@@ -291,7 +291,7 @@
                 mReceivedDisplayEvents.pop_front();
 
                 ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
-                         "event hotplug: displayId %s, connected %d\t",
+                         "event hotplug: displayId %s, connected %d",
                          to_string(event.header.displayId).c_str(), event.hotplug.connected);
 
                 if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
@@ -314,7 +314,7 @@
                 mReceivedDisplayEvents.pop_front();
 
                 ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED,
-                         "event config: displayId %s, configId %d\t",
+                         "event config: displayId %s, configId %d",
                          to_string(event.header.displayId).c_str(), event.config.configId);
 
                 if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
@@ -341,7 +341,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         {
@@ -372,7 +372,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
 
@@ -403,7 +403,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
@@ -456,7 +456,7 @@
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate));
-                waitForDisplayTransaction();
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
@@ -487,7 +487,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
     }
@@ -510,7 +510,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
@@ -562,7 +562,7 @@
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate));
-                waitForDisplayTransaction();
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
@@ -593,7 +593,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
     }
@@ -626,7 +626,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
@@ -669,7 +669,7 @@
                     .WillOnce(Return(V2_1::Error::NONE));
         }
 
-        for (int i = 0; i < configs.size(); i++) {
+        for (size_t i = 0; i < configs.size(); i++) {
             const auto& config = configs[i];
             if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
@@ -679,7 +679,7 @@
                                                                configs[i].refreshRate,
                                                                configs[i].refreshRate,
                                                                configs[i].refreshRate));
-                waitForDisplayTransaction();
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
@@ -726,7 +726,7 @@
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate));
-                waitForDisplayTransaction();
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
@@ -773,7 +773,7 @@
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate));
-                waitForDisplayTransaction();
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
                 EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
@@ -804,7 +804,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
     }
@@ -815,7 +815,7 @@
         mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
 
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(PRIMARY_DISPLAY);
 
         EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
         {
@@ -840,7 +840,7 @@
         mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
 
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(PRIMARY_DISPLAY);
 
         EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
 
@@ -856,6 +856,121 @@
         }
     }
 
+    void Test_SubsequentHotplugConnectUpdatesDisplay(Display hwcDisplayId) {
+        ALOGD("DisplayTest::Test_SubsequentHotplugConnectUpdatesDisplay");
+
+        // Send a hotplug connected event to set up the initial display modes.
+        // The primary display is already connected so this will update it.
+        // If we're running the test of an external display this will create it.
+        setExpectationsForConfigs(hwcDisplayId,
+                                  {{.id = 1,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 11'111'111,
+                                    .group = 1}},
+                                  /* activeConfig */ 1, 11'111'111);
+
+        mFakeComposerClient->hotplugDisplay(hwcDisplayId,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction(hwcDisplayId);
+        EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true));
+
+        const auto displayId = physicalIdFromHwcDisplayId(hwcDisplayId);
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(displayId);
+        EXPECT_FALSE(display == nullptr);
+
+        // Verify that the active mode and the supported moded are updated
+        {
+            DisplayConfig config;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+            EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+            EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+            Vector<DisplayConfig> configs;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+            EXPECT_EQ(configs.size(), 1);
+        }
+
+        // Send another hotplug connected event
+        setExpectationsForConfigs(hwcDisplayId,
+                                  {
+                                          {.id = 1,
+                                           .w = 800,
+                                           .h = 1600,
+                                           .vsyncPeriod = 16'666'666,
+                                           .group = 1},
+                                          {.id = 2,
+                                           .w = 800,
+                                           .h = 1600,
+                                           .vsyncPeriod = 11'111'111,
+                                           .group = 1},
+                                          {.id = 3,
+                                           .w = 800,
+                                           .h = 1600,
+                                           .vsyncPeriod = 8'333'333,
+                                           .group = 1},
+                                  },
+                                  /* activeConfig */ 1, 16'666'666);
+
+        mFakeComposerClient->hotplugDisplay(hwcDisplayId,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction(hwcDisplayId);
+        EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true));
+
+        // Verify that the active mode and the supported moded are updated
+        {
+            DisplayConfig config;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+            EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+            EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+        }
+
+        Vector<DisplayConfig> configs;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+        EXPECT_EQ(configs.size(), 3);
+
+        EXPECT_EQ(ui::Size(800, 1600), configs[0].resolution);
+        EXPECT_EQ(1e9f / 16'666'666, configs[0].refreshRate);
+
+        EXPECT_EQ(ui::Size(800, 1600), configs[1].resolution);
+        EXPECT_EQ(1e9f / 11'111'111, configs[1].refreshRate);
+
+        EXPECT_EQ(ui::Size(800, 1600), configs[2].resolution);
+        EXPECT_EQ(1e9f / 8'333'333, configs[2].refreshRate);
+
+        // Verify that we are able to switch to any of the modes
+        for (int i = configs.size() - 1; i >= 0; i--) {
+            const auto hwcId = i + 1;
+            // Set up HWC expectations for the mode change
+            if (mIs2_4Client) {
+                EXPECT_CALL(*mMockComposer,
+                            setActiveConfigWithConstraints(hwcDisplayId, hwcId, _, _))
+                        .WillOnce(Return(V2_4::Error::NONE));
+            } else {
+                EXPECT_CALL(*mMockComposer, setActiveConfig(hwcDisplayId, hwcId))
+                        .WillOnce(Return(V2_1::Error::NONE));
+            }
+
+            EXPECT_EQ(NO_ERROR,
+                      SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
+                                                                          configs[i].refreshRate,
+                                                                          configs[i].refreshRate,
+                                                                          configs[i].refreshRate,
+                                                                          configs[i].refreshRate));
+            // We need to refresh twice - once to apply the pending mode change request,
+            // and once to process the change.
+            waitForDisplayTransaction(hwcDisplayId);
+            waitForDisplayTransaction(hwcDisplayId);
+            EXPECT_TRUE(waitForConfigChangedEvent(hwcDisplayId, i))
+                    << "Failure while switching to mode " << i;
+
+            DisplayConfig config;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+            EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+            EXPECT_EQ(configs[i].refreshRate, config.refreshRate);
+        }
+    }
+
     sp<V2_1::IComposer> mFakeService;
     sp<SurfaceComposerClient> mComposerClient;
 
@@ -911,6 +1026,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 using DisplayTest_2_2 = DisplayTest<FakeComposerService_2_2>;
 
 TEST_F(DisplayTest_2_2, HotplugOneConfig) {
@@ -933,6 +1056,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 using DisplayTest_2_3 = DisplayTest<FakeComposerService_2_3>;
 
 TEST_F(DisplayTest_2_3, HotplugOneConfig) {
@@ -955,6 +1086,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 using DisplayTest_2_4 = DisplayTest<FakeComposerService_2_4>;
 
 TEST_F(DisplayTest_2_4, HotplugOneConfig) {
@@ -977,6 +1116,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 ////////////////////////////////////////////////
 
 template <typename FakeComposerService>
@@ -1639,82 +1786,6 @@
         EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
     }
 
-    void Test_DetachChildrenSameClient() {
-        {
-            TransactionScope ts(*Base::sFakeComposer);
-            ts.show(mChild);
-            ts.setPosition(mChild, 10, 10);
-            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
-        }
-
-        auto referenceFrame = Base::mBaseFrame;
-        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-        referenceFrame[CHILD_LAYER].mDisplayFrame =
-                hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
-        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
-        {
-            TransactionScope ts(*Base::sFakeComposer);
-            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
-            ts.detachChildren(Base::mFGSurfaceControl);
-        }
-
-        {
-            TransactionScope ts(*Base::sFakeComposer);
-            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
-            ts.hide(mChild);
-        }
-
-        std::vector<RenderState> refFrame(2);
-        refFrame[Base::BG_LAYER] = Base::mBaseFrame[Base::BG_LAYER];
-        refFrame[Base::FG_LAYER] = Base::mBaseFrame[Base::FG_LAYER];
-
-        EXPECT_TRUE(framesAreSame(refFrame, Base::sFakeComposer->getLatestFrame()));
-    }
-
-    void Test_DetachChildrenDifferentClient() {
-        sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-        sp<SurfaceControl> childNewClient =
-                newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
-                                                 PIXEL_FORMAT_RGBA_8888, 0,
-                                                 Base::mFGSurfaceControl->getHandle());
-        ASSERT_TRUE(childNewClient != nullptr);
-        ASSERT_TRUE(childNewClient->isValid());
-        fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
-
-        {
-            TransactionScope ts(*Base::sFakeComposer);
-            ts.hide(mChild);
-            ts.show(childNewClient);
-            ts.setPosition(childNewClient, 10, 10);
-            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
-        }
-
-        auto referenceFrame = Base::mBaseFrame;
-        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-        referenceFrame[CHILD_LAYER].mDisplayFrame =
-                hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
-        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-
-        {
-            TransactionScope ts(*Base::sFakeComposer);
-            ts.detachChildren(Base::mFGSurfaceControl);
-            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
-        }
-
-        {
-            TransactionScope ts(*Base::sFakeComposer);
-            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
-            ts.setPosition(childNewClient, 0, 0);
-            ts.hide(childNewClient);
-        }
-
-        // Nothing should have changed. The child control becomes a no-op
-        // zombie on detach. See comments for detachChildren in the
-        // SurfaceControl.h file.
-        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
-    }
-
     // Regression test for b/37673612
     void Test_ChildrenWithParentBufferTransform() {
         {
@@ -1815,14 +1886,6 @@
     Test_ReparentChildren();
 }
 
-TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenSameClient) {
-    Test_DetachChildrenSameClient();
-}
-
-TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenDifferentClient) {
-    Test_DetachChildrenDifferentClient();
-}
-
 // Regression test for b/37673612
 TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
     Test_ChildrenWithParentBufferTransform();
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f2051d9..b696a6d 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -62,15 +62,9 @@
 
 using testing::_;
 using testing::AtLeast;
-using testing::Between;
-using testing::ByMove;
 using testing::DoAll;
-using testing::Field;
-using testing::Invoke;
 using testing::IsNull;
 using testing::Mock;
-using testing::NotNull;
-using testing::Ref;
 using testing::Return;
 using testing::ReturnRef;
 using testing::SetArgPointee;
@@ -86,7 +80,6 @@
 constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
 
-constexpr int DEFAULT_CONFIG_ID = 0;
 constexpr int DEFAULT_TEXTURE_ID = 6000;
 constexpr int DEFAULT_LAYER_STACK = 7000;
 
@@ -147,7 +140,7 @@
 
         EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
         EXPECT_CALL(*vsyncTracker, currentPeriod())
-                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
         EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
 
         constexpr ISchedulerCallback* kCallback = nullptr;
@@ -548,12 +541,6 @@
         setupLatchedBuffer(test, layer);
     }
 
-    static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) {
-        // BufferLayer::onPostComposition(), when there is no present fence
-        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _))
-                .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
-    }
-
     static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
         if (!test->mDisplayOff) {
             // TODO: Coverage of other values
@@ -632,8 +619,6 @@
                     .Times(1);
             EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
         }
-
-        setupBufferLayerPostFrameCallExpectations(test);
     }
 
     static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
@@ -793,7 +778,6 @@
 
     static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
         setupInsecureREBufferCompositionCommonCallExpectations(test);
-        Base::setupBufferLayerPostFrameCallExpectations(test);
     }
 
     static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index e2584e2..6e9f09b 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra"
 
 #include "gmock/gmock-spec-builders.h"
 #include "mock/MockTimeStats.h"
@@ -177,16 +174,17 @@
 static constexpr const uid_t sUidOne = 0;
 static constexpr pid_t sPidOne = 10;
 static constexpr pid_t sPidTwo = 20;
+static constexpr int32_t sInputEventId = 5;
 
 TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
-    EXPECT_EQ(getPredictions().size(), 1);
+    EXPECT_EQ(getPredictions().size(), 1u);
     flushTokens(systemTime() + maxTokenRetentionTime);
     int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     std::optional<TimelineItem> predictions = mTokenManager->getPredictionsForToken(token1);
 
     // token1 should have expired
-    EXPECT_EQ(getPredictions().size(), 1);
+    EXPECT_EQ(getPredictions().size(), 1u);
     EXPECT_EQ(predictions.has_value(), false);
 
     predictions = mTokenManager->getPredictionsForToken(token2);
@@ -194,16 +192,16 @@
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPid) {
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne,
                                                                     sLayerNameOne, sLayerNameOne);
-    auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidTwo, sUidOne,
+    auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({}, sPidTwo, sUidOne,
                                                                     sLayerNameOne, sLayerNameOne);
     EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne);
     EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo);
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) {
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne,
                                                                    sLayerNameOne, sLayerNameOne);
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None);
 }
@@ -211,21 +209,33 @@
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
     flushTokens(systemTime() + maxTokenRetentionTime);
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
-                                                                   sLayerNameOne, sLayerNameOne);
+    auto surfaceFrame =
+            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
 
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired);
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
-                                                                   sLayerNameOne, sLayerNameOne);
+    auto surfaceFrame =
+            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
 
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid);
     EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true);
 }
 
+TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) {
+    int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
+    constexpr int32_t inputEventId = 1;
+    auto surfaceFrame =
+            mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+
+    EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId());
+}
+
 TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) {
     // Global increment
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
@@ -234,8 +244,9 @@
 
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
-                                                                    sLayerNameOne, sLayerNameOne);
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(token1, 20, 11);
@@ -264,11 +275,11 @@
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameTwo, sLayerNameTwo);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameTwo, sLayerNameTwo);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
@@ -288,8 +299,8 @@
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame3 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
     surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame3);
@@ -320,8 +331,9 @@
         int64_t sfToken = mTokenManager->generateTokenForPredictions(
                 {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
-                                                           sLayerNameOne, sLayerNameOne);
+                mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId},
+                                                           sPidOne, sUidOne, sLayerNameOne,
+                                                           sLayerNameOne);
         mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
@@ -341,8 +353,8 @@
     int64_t sfToken = mTokenManager->generateTokenForPredictions(
             {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
@@ -356,18 +368,18 @@
 }
 
 TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) {
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0,
-                                                                   "acquireFenceAfterQueue",
-                                                                   "acquireFenceAfterQueue");
+    auto surfaceFrame =
+            mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue",
+                                                       "acquireFenceAfterQueue");
     surfaceFrame->setActualQueueTime(123);
     surfaceFrame->setAcquireFenceTime(456);
     EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
 }
 
 TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0,
-                                                                   "acquireFenceAfterQueue",
-                                                                   "acquireFenceAfterQueue");
+    auto surfaceFrame =
+            mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue",
+                                                       "acquireFenceAfterQueue");
     surfaceFrame->setActualQueueTime(456);
     surfaceFrame->setAcquireFenceTime(123);
     EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
@@ -383,8 +395,8 @@
     // Size shouldn't exceed maxDisplayFrames - 64
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
-                                                           sLayerNameOne, sLayerNameOne);
+                mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
+                                                           sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -395,15 +407,15 @@
 
     // Increase the size to 256
     mFrameTimeline->setMaxDisplayFrames(256);
-    EXPECT_EQ(*maxDisplayFrames, 256);
+    EXPECT_EQ(*maxDisplayFrames, 256u);
     // Global increment
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
             .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
 
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
-                                                           sLayerNameOne, sLayerNameOne);
+                mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
+                                                           sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -414,15 +426,15 @@
 
     // Shrink the size to 128
     mFrameTimeline->setMaxDisplayFrames(128);
-    EXPECT_EQ(*maxDisplayFrames, 128);
+    EXPECT_EQ(*maxDisplayFrames, 128u);
     // Global increment
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
             .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
 
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
-                                                           sLayerNameOne, sLayerNameOne);
+                mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
+                                                           sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -449,8 +461,8 @@
              std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
              std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
                                 11);
@@ -478,8 +490,8 @@
              std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
              std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
                                 30);
@@ -507,8 +519,8 @@
              std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
              std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(
             std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
     mFrameTimeline->setSfWakeUp(sfToken1,
@@ -542,8 +554,9 @@
 
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
-                                                                    sLayerNameOne, sLayerNameOne);
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(token1, 20, 11);
@@ -558,7 +571,7 @@
     mFrameTimeline->setSfPresent(55, presentFence2);
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 0);
+    EXPECT_EQ(packets.size(), 0u);
 }
 
 TEST_F(FrameTimelineTest, tracing_sanityTest) {
@@ -573,8 +586,9 @@
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
-                                                                    sLayerNameOne, sLayerNameOne);
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(token2, 20, 11);
@@ -594,7 +608,7 @@
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
     // Display Frame 1 has 8 packets - 4 from DisplayFrame and 4 from SurfaceFrame.
-    EXPECT_EQ(packets.size(), 8);
+    EXPECT_EQ(packets.size(), 8u);
 }
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) {
@@ -622,7 +636,7 @@
     tracingSession->StopBlocking();
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 0);
+    EXPECT_EQ(packets.size(), 0u);
 }
 
 TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) {
@@ -635,7 +649,7 @@
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne,
                                                                     sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
@@ -657,7 +671,7 @@
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
     // Display Frame 1 has 4 packets (SurfaceFrame shouldn't be traced since it has an invalid
     // token).
-    EXPECT_EQ(packets.size(), 4);
+    EXPECT_EQ(packets.size(), 4u);
 }
 
 void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received,
@@ -791,12 +805,12 @@
     tracingSession->StopBlocking();
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 4);
+    EXPECT_EQ(packets.size(), 4u);
 
     // Packet - 0 : ExpectedDisplayFrameStart
     const auto& packet0 = packets[0];
     ASSERT_TRUE(packet0.has_timestamp());
-    EXPECT_EQ(packet0.timestamp(), 10);
+    EXPECT_EQ(packet0.timestamp(), 10u);
     ASSERT_TRUE(packet0.has_frame_timeline_event());
 
     const auto& event0 = packet0.frame_timeline_event();
@@ -807,7 +821,7 @@
     // Packet - 1 : FrameEnd (ExpectedDisplayFrame)
     const auto& packet1 = packets[1];
     ASSERT_TRUE(packet1.has_timestamp());
-    EXPECT_EQ(packet1.timestamp(), 25);
+    EXPECT_EQ(packet1.timestamp(), 25u);
     ASSERT_TRUE(packet1.has_frame_timeline_event());
 
     const auto& event1 = packet1.frame_timeline_event();
@@ -818,7 +832,7 @@
     // Packet - 2 : ActualDisplayFrameStart
     const auto& packet2 = packets[2];
     ASSERT_TRUE(packet2.has_timestamp());
-    EXPECT_EQ(packet2.timestamp(), 20);
+    EXPECT_EQ(packet2.timestamp(), 20u);
     ASSERT_TRUE(packet2.has_frame_timeline_event());
 
     const auto& event2 = packet2.frame_timeline_event();
@@ -829,7 +843,7 @@
     // Packet - 3 : FrameEnd (ActualDisplayFrame)
     const auto& packet3 = packets[3];
     ASSERT_TRUE(packet3.has_timestamp());
-    EXPECT_EQ(packet3.timestamp(), 26);
+    EXPECT_EQ(packet3.timestamp(), 26u);
     ASSERT_TRUE(packet3.has_frame_timeline_event());
 
     const auto& event3 = packet3.frame_timeline_event();
@@ -853,8 +867,8 @@
     int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setActualStartTime(0);
     surfaceFrame1->setActualQueueTime(15);
     surfaceFrame1->setAcquireFenceTime(20);
@@ -904,12 +918,12 @@
     tracingSession->StopBlocking();
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 8);
+    EXPECT_EQ(packets.size(), 8u);
 
     // Packet - 4 : ExpectedSurfaceFrameStart
     const auto& packet4 = packets[4];
     ASSERT_TRUE(packet4.has_timestamp());
-    EXPECT_EQ(packet4.timestamp(), 10);
+    EXPECT_EQ(packet4.timestamp(), 10u);
     ASSERT_TRUE(packet4.has_frame_timeline_event());
 
     const auto& event4 = packet4.frame_timeline_event();
@@ -920,7 +934,7 @@
     // Packet - 5 : FrameEnd (ExpectedSurfaceFrame)
     const auto& packet5 = packets[5];
     ASSERT_TRUE(packet5.has_timestamp());
-    EXPECT_EQ(packet5.timestamp(), 25);
+    EXPECT_EQ(packet5.timestamp(), 25u);
     ASSERT_TRUE(packet5.has_frame_timeline_event());
 
     const auto& event5 = packet5.frame_timeline_event();
@@ -931,7 +945,7 @@
     // Packet - 6 : ActualSurfaceFrameStart
     const auto& packet6 = packets[6];
     ASSERT_TRUE(packet6.has_timestamp());
-    EXPECT_EQ(packet6.timestamp(), 10);
+    EXPECT_EQ(packet6.timestamp(), 10u);
     ASSERT_TRUE(packet6.has_frame_timeline_event());
 
     const auto& event6 = packet6.frame_timeline_event();
@@ -942,7 +956,7 @@
     // Packet - 7 : FrameEnd (ActualSurfaceFrame)
     const auto& packet7 = packets[7];
     ASSERT_TRUE(packet7.has_timestamp());
-    EXPECT_EQ(packet7.timestamp(), 20);
+    EXPECT_EQ(packet7.timestamp(), 20u);
     ASSERT_TRUE(packet7.has_frame_timeline_event());
 
     const auto& event7 = packet7.frame_timeline_event();
@@ -961,8 +975,8 @@
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
@@ -1126,8 +1140,8 @@
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(16);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1145,8 +1159,8 @@
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(36);
     mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1199,8 +1213,8 @@
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(16);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1218,8 +1232,8 @@
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(36);
     mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1270,8 +1284,8 @@
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(40);
     mFrameTimeline->setSfWakeUp(sfToken1, 42, 11);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1316,8 +1330,8 @@
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(26);
     mFrameTimeline->setSfWakeUp(sfToken1, 32, 11);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1335,8 +1349,8 @@
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(40);
     mFrameTimeline->setSfWakeUp(sfToken2, 43, 11);
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1390,8 +1404,8 @@
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 56, 60});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 116, 120});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(50);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, 30);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1409,8 +1423,8 @@
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
-                                                       sLayerNameOne, sLayerNameOne);
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(84);
     mFrameTimeline->setSfWakeUp(sfToken2, 112, 30);
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
@@ -1456,6 +1470,3 @@
               JankType::AppDeadlineMissed | JankType::BufferStuffing);
 }
 } // namespace android::frametimeline
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 1e24c0a..6b82170 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -175,90 +175,5 @@
     EXPECT_EQ(hal::Error::UNSUPPORTED, result);
 }
 
-class HWComposerConfigsTest : public testing::Test {
-public:
-    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
-    MockHWC2ComposerCallback mCallback;
-
-    void setActiveConfig(Config config) {
-        EXPECT_CALL(*mHal, getActiveConfig(_, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(config), Return(V2_1::Error::NONE)));
-    }
-
-    void setDisplayConfigs(std::vector<Config> configs) {
-        EXPECT_CALL(*mHal, getDisplayConfigs(_, _))
-                .WillOnce(DoAll(SetArgPointee<1>(configs), Return(V2_1::Error::NONE)));
-        EXPECT_CALL(*mHal, getDisplayAttribute(_, _, _, _))
-                .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE)));
-    }
-
-    void testSetActiveModeWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
-};
-
-void HWComposerConfigsTest::testSetActiveModeWithConstraintsCommon(
-        bool isVsyncPeriodSwitchSupported) {
-    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
-    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
-    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)).WillOnce(Return(V2_4::Error::UNSUPPORTED));
-    EXPECT_CALL(*mHal, registerCallback(_));
-    EXPECT_CALL(*mHal, setVsyncEnabled(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
-    EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _))
-            .WillRepeatedly(Return(V2_1::Error::UNSUPPORTED));
-    EXPECT_CALL(*mHal, setClientTargetSlotCount(_)).WillRepeatedly(Return(V2_1::Error::NONE));
-
-    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported())
-            .WillRepeatedly(Return(isVsyncPeriodSwitchSupported));
-
-    if (isVsyncPeriodSwitchSupported) {
-        EXPECT_CALL(*mHal, setActiveConfigWithConstraints(_, _, _, _))
-                .WillRepeatedly(Return(V2_4::Error::NONE));
-    } else {
-        EXPECT_CALL(*mHal, setActiveConfig(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
-    }
-
-    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
-    hwc.setConfiguration(&mCallback, 123);
-
-    setDisplayConfigs({15});
-    setActiveConfig(15);
-
-    const auto physicalId = PhysicalDisplayId::fromPort(0);
-    const hal::HWDisplayId hwcId = 0;
-    hwc.allocatePhysicalDisplay(hwcId, physicalId);
-
-    hal::VsyncPeriodChangeConstraints constraints;
-    constraints.desiredTimeNanos = systemTime();
-    constraints.seamlessRequired = false;
-
-    hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-    constexpr Config kConfigIndex = 0;
-    const auto status =
-            hwc.setActiveModeWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
-    EXPECT_EQ(NO_ERROR, status);
-
-    const std::vector<Config> kConfigs{7, 8, 9, 10, 11};
-    // Change the set of supported modes.
-    setDisplayConfigs(kConfigs);
-    setActiveConfig(11);
-    hwc.onHotplug(hwcId, hal::Connection::CONNECTED);
-    hwc.allocatePhysicalDisplay(hwcId, physicalId);
-
-    for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
-        const auto status =
-                hwc.setActiveModeWithConstraints(physicalId,
-                                                 static_cast<hal::HWConfigId>(configIndex),
-                                                 constraints, &timeline);
-        EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
-    }
-}
-
-TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingSupported) {
-    testSetActiveModeWithConstraintsCommon(/*supported=*/true);
-}
-
-TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingNotSupported) {
-    testSetActiveModeWithConstraintsCommon(/*supported=*/false);
-}
-
 } // namespace
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index c5deb7c..abecd4b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -144,7 +144,7 @@
 
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     EXPECT_CALL(*vsyncTracker, currentPeriod())
-            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
                             std::move(eventThread), std::move(sfEventThread));
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index e060df2..a6d07d0 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -185,7 +185,7 @@
 
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     EXPECT_CALL(*vsyncTracker, currentPeriod())
-            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
                             std::move(eventThread), std::move(sfEventThread));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
index 8552e15..b713334 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -669,7 +669,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(newWidth, oldHeight))).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -714,7 +714,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(oldWidth, newHeight))).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -764,7 +764,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*displaySurface, resizeBuffers(kNewWidth, kNewHeight)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(kNewSize.getSize())).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2701f47..3787c43 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -41,6 +41,7 @@
 #include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
 #include "TestableScheduler.h"
+#include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockDisplayIdGenerator.h"
 #include "mock/MockFrameTimeline.h"
 #include "mock/MockFrameTracer.h"
@@ -353,7 +354,8 @@
                                 bool regionSampling) {
         ScreenCaptureResults captureResults;
         return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem,
-                                                regionSampling, captureResults);
+                                                regionSampling, false /* grayscale */,
+                                                captureResults);
     }
 
     auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid,
@@ -366,18 +368,17 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
-    auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
+    auto& getTransactionQueue() { return mFlinger->mTransactionQueue; }
+    auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
 
-    auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
-                             const Vector<DisplayState>& displays, uint32_t flags,
-                             const sp<IBinder>& applyToken,
-                             const InputWindowCommands& inputWindowCommands,
-                             int64_t desiredPresentTime, bool isAutoTimestamp,
-                             const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
-                             std::vector<ListenerCallbacks>& listenerCallbacks,
-                             uint64_t transactionId) {
-        return mFlinger->setTransactionState(frameTimelineVsyncId, states, displays, flags,
-                                             applyToken, inputWindowCommands, desiredPresentTime,
+    auto setTransactionState(
+            const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
+            const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+            const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+            bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+            std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
+        return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
+                                             inputWindowCommands, desiredPresentTime,
                                              isAutoTimestamp, uncacheBuffer, hasListenerCallbacks,
                                              listenerCallbacks, transactionId);
     }
@@ -478,7 +479,7 @@
         static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000;
         static constexpr int32_t DEFAULT_WIDTH = 1920;
         static constexpr int32_t DEFAULT_HEIGHT = 1280;
-        static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+        static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'666;
         static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
         static constexpr int32_t DEFAULT_DPI = 320;
         static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0;
@@ -503,8 +504,8 @@
             return *this;
         }
 
-        auto& setRefreshRate(int32_t refreshRate) {
-            mRefreshRate = refreshRate;
+        auto& setVsyncPeriod(int32_t vsyncPeriod) {
+            mVsyncPeriod = vsyncPeriod;
             return *this;
         }
 
@@ -533,7 +534,12 @@
             return *this;
         }
 
-        void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
+        void inject(TestableSurfaceFlinger* flinger, Hwc2::mock::Composer* composer) {
+            using ::testing::_;
+            using ::testing::DoAll;
+            using ::testing::Return;
+            using ::testing::SetArgPointee;
+
             static const std::unordered_set<hal::Capability> defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
 
@@ -548,15 +554,39 @@
             display->setPowerMode(mPowerMode);
             flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
 
-            auto config = DisplayMode::Builder(mActiveConfig)
-                                  .setWidth(mWidth)
-                                  .setHeight(mHeight)
-                                  .setVsyncPeriod(mRefreshRate)
-                                  .setDpiX(mDpiX)
-                                  .setDpiY(mDpiY)
-                                  .setConfigGroup(mConfigGroup)
-                                  .build();
-            flinger->mutableHwcDisplayData()[mDisplayId].modes.push_back(config);
+            EXPECT_CALL(*composer, getDisplayConfigs(mHwcDisplayId, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{mActiveConfig}),
+                                  Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::WIDTH, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mWidth), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::HEIGHT,
+                                            _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mHeight), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig,
+                                            hal::Attribute::VSYNC_PERIOD, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(mVsyncPeriod), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_X, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiX), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_Y, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiY), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig,
+                                            hal::Attribute::CONFIG_GROUP, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(mConfigGroup), Return(hal::Error::NONE)));
 
             if (mHwcDisplayType == hal::DisplayType::PHYSICAL) {
                 const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId);
@@ -582,10 +612,10 @@
         hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
         int32_t mWidth = DEFAULT_WIDTH;
         int32_t mHeight = DEFAULT_HEIGHT;
-        int32_t mRefreshRate = DEFAULT_REFRESH_RATE;
+        int32_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD;
         int32_t mDpiX = DEFAULT_DPI;
-        int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         int32_t mDpiY = DEFAULT_DPI;
+        int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
         hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
         const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
@@ -603,6 +633,21 @@
                 mHwcDisplayId(hwcDisplayId) {
             mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;
+
+            mActiveModeId = DisplayModeId(0);
+            DisplayModePtr activeMode =
+                    DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
+                            .setId(mActiveModeId)
+                            .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
+                            .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
+                            .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
+                            .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
+                            .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
+                            .setConfigGroup(0)
+                            .build();
+
+            DisplayModes modes{activeMode};
+            mCreationArgs.supportedModes = modes;
         }
 
         sp<IBinder> token() const { return mDisplayToken; }
@@ -625,6 +670,16 @@
 
         auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
 
+        auto& setActiveMode(DisplayModeId mode) {
+            mActiveModeId = mode;
+            return *this;
+        }
+
+        auto& setSupportedModes(DisplayModes mode) {
+            mCreationArgs.supportedModes = mode;
+            return *this;
+        }
+
         auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) {
             mCreationArgs.nativeWindow = nativeWindow;
             return *this;
@@ -677,6 +732,9 @@
             state.isSecure = mCreationArgs.isSecure;
 
             sp<DisplayDevice> device = new DisplayDevice(mCreationArgs);
+            if (!device->isVirtual()) {
+                device->setActiveMode(mActiveModeId);
+            }
             mFlinger.mutableDisplays().emplace(mDisplayToken, device);
             mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
             mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
@@ -693,6 +751,7 @@
         sp<BBinder> mDisplayToken = new BBinder();
         DisplayDeviceCreationArgs mCreationArgs;
         const std::optional<hal::HWDisplayId> mHwcDisplayId;
+        DisplayModeId mActiveModeId;
     };
 
 private:
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 06275c6..eb2c1ba 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
 
 #undef LOG_TAG
 #define LOG_TAG "CompositionTest"
@@ -76,7 +72,7 @@
 
         EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
         EXPECT_CALL(*mVSyncTracker, currentPeriod())
-                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
 
         mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
                                 std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
@@ -100,50 +96,50 @@
         InputWindowCommands inputWindowCommands;
         int64_t desiredPresentTime = 0;
         bool isAutoTimestamp = true;
-        int64_t frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+        FrameTimelineInfo frameTimelineInfo;
         client_cache_t uncacheBuffer;
-        int64_t id = -1;
+        uint64_t id = static_cast<uint64_t>(-1);
+        static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1));
     };
 
     void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
-        EXPECT_EQ(0, info.states.size());
-        EXPECT_EQ(0, state.states.size());
+        EXPECT_EQ(0u, info.states.size());
+        EXPECT_EQ(0u, state.states.size());
 
-        EXPECT_EQ(0, info.displays.size());
-        EXPECT_EQ(0, state.displays.size());
+        EXPECT_EQ(0u, info.displays.size());
+        EXPECT_EQ(0u, state.displays.size());
         EXPECT_EQ(info.flags, state.flags);
         EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
     }
 
     void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
                      int64_t desiredPresentTime, bool isAutoTimestamp,
-                     int64_t frameTimelineVsyncId) {
+                     const FrameTimelineInfo& frameTimelineInfo) {
         mTransactionNumber++;
         transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
         transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
         transaction.desiredPresentTime = desiredPresentTime;
         transaction.isAutoTimestamp = isAutoTimestamp;
-        transaction.frameTimelineVsyncId = frameTimelineVsyncId;
+        transaction.frameTimelineInfo = frameTimelineInfo;
     }
 
     void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         // called in SurfaceFlinger::signalTransaction
         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
         EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime()));
         TransactionInfo transaction;
         setupSingle(transaction, flags, syncInputWindows,
                     /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                    ISurfaceComposer::INVALID_VSYNC_ID);
+                    FrameTimelineInfo{});
         nsecs_t applicationTime = systemTime();
-        mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+        mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
                                      transaction.displays, transaction.flags,
                                      transaction.applyToken, transaction.inputWindowCommands,
                                      transaction.desiredPresentTime, transaction.isAutoTimestamp,
                                      transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
                                      transaction.id);
 
-        // This transaction should not have been placed on the transaction queue.
         // If transaction is synchronous or syncs input windows, SF
         // applyTransactionState should time out (5s) wating for SF to commit
         // the transaction or to receive a signal that syncInputWindows has
@@ -154,12 +150,13 @@
         } else {
             EXPECT_LE(returnedTime, applicationTime + s2ns(5));
         }
+        // Each transaction should have been placed on the transaction queue
         auto transactionQueue = mFlinger.getTransactionQueue();
-        EXPECT_EQ(0, transactionQueue.size());
+        EXPECT_EQ(1u, transactionQueue.size());
     }
 
     void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         // called in SurfaceFlinger::signalTransaction
         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
 
@@ -170,10 +167,9 @@
                 .WillOnce(Return(time + nsecs_t(5 * 1e8)));
         TransactionInfo transaction;
         setupSingle(transaction, flags, syncInputWindows,
-                    /*desiredPresentTime*/ time + s2ns(1), false,
-                    ISurfaceComposer::INVALID_VSYNC_ID);
+                    /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{});
         nsecs_t applicationSentTime = systemTime();
-        mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+        mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
                                      transaction.displays, transaction.flags,
                                      transaction.applyToken, transaction.inputWindowCommands,
                                      transaction.desiredPresentTime, transaction.isAutoTimestamp,
@@ -184,11 +180,11 @@
         EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
         // This transaction should have been placed on the transaction queue
         auto transactionQueue = mFlinger.getTransactionQueue();
-        EXPECT_EQ(1, transactionQueue.size());
+        EXPECT_EQ(1u, transactionQueue.size());
     }
 
     void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         // called in SurfaceFlinger::signalTransaction
         nsecs_t time = systemTime();
         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -197,18 +193,17 @@
         // transaction that should go on the pending thread
         TransactionInfo transactionA;
         setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
-                    /*desiredPresentTime*/ time + s2ns(1), false,
-                    ISurfaceComposer::INVALID_VSYNC_ID);
+                    /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{});
 
         // transaction that would not have gone on the pending thread if not
         // blocked
         TransactionInfo transactionB;
         setupSingle(transactionB, flags, syncInputWindows,
                     /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                    ISurfaceComposer::INVALID_VSYNC_ID);
+                    FrameTimelineInfo{});
 
         nsecs_t applicationSentTime = systemTime();
-        mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states,
+        mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
                                      transactionA.displays, transactionA.flags,
                                      transactionA.applyToken, transactionA.inputWindowCommands,
                                      transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
@@ -219,9 +214,11 @@
         // (5s is the timeout period that applyTransactionState waits for SF to
         // commit the transaction)
         EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+        // transaction that would goes to pending transaciton queue.
+        mFlinger.flushTransactionQueues();
 
         applicationSentTime = systemTime();
-        mFlinger.setTransactionState(transactionB.frameTimelineVsyncId, transactionB.states,
+        mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
                                      transactionB.displays, transactionB.flags,
                                      transactionB.applyToken, transactionB.inputWindowCommands,
                                      transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
@@ -238,12 +235,15 @@
             EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
         }
 
+        // transaction that would goes to pending transaciton queue.
+        mFlinger.flushTransactionQueues();
+
         // check that there is one binder on the pending queue.
-        auto transactionQueue = mFlinger.getTransactionQueue();
-        EXPECT_EQ(1, transactionQueue.size());
+        auto transactionQueue = mFlinger.getPendingTransactionQueue();
+        EXPECT_EQ(1u, transactionQueue.size());
 
         auto& [applyToken, transactionStates] = *(transactionQueue.begin());
-        EXPECT_EQ(2, transactionStates.size());
+        EXPECT_EQ(2u, transactionStates.size());
 
         auto& transactionStateA = transactionStates.front();
         transactionStates.pop();
@@ -258,7 +258,7 @@
 };
 
 TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
-    ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+    ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
     // called in SurfaceFlinger::signalTransaction
     EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
 
@@ -268,20 +268,17 @@
             .WillOnce(Return(s2ns(2)));
     TransactionInfo transactionA; // transaction to go on pending queue
     setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
-                /*desiredPresentTime*/ s2ns(1), false, ISurfaceComposer::INVALID_VSYNC_ID);
-    mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states,
+                /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{});
+    mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
                                  transactionA.displays, transactionA.flags, transactionA.applyToken,
                                  transactionA.inputWindowCommands, transactionA.desiredPresentTime,
                                  transactionA.isAutoTimestamp, transactionA.uncacheBuffer,
                                  mHasListenerCallbacks, mCallbacks, transactionA.id);
 
     auto& transactionQueue = mFlinger.getTransactionQueue();
-    ASSERT_EQ(1, transactionQueue.size());
+    ASSERT_EQ(1u, transactionQueue.size());
 
-    auto& [applyToken, transactionStates] = *(transactionQueue.begin());
-    ASSERT_EQ(1, transactionStates.size());
-
-    auto& transactionState = transactionStates.front();
+    auto& transactionState = transactionQueue.front();
     checkEqual(transactionA, transactionState);
 
     // because flushing uses the cached expected present time, we send an empty
@@ -289,8 +286,8 @@
     // different process) to re-query and reset the cached expected present time
     TransactionInfo empty;
     empty.applyToken = sp<IBinder>();
-    mFlinger.setTransactionState(empty.frameTimelineVsyncId, empty.states, empty.displays,
-                                 empty.flags, empty.applyToken, empty.inputWindowCommands,
+    mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags,
+                                 empty.applyToken, empty.inputWindowCommands,
                                  empty.desiredPresentTime, empty.isAutoTimestamp,
                                  empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id);
 
@@ -298,7 +295,7 @@
     // passed
     mFlinger.flushTransactionQueues();
 
-    EXPECT_EQ(0, transactionQueue.size());
+    EXPECT_EQ(0u, transactionQueue.size());
 }
 
 TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
@@ -343,6 +340,3 @@
     EXPECT_EQ(nullptr, ret.promote().get());
 }
 } // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index a13f93b..2fefa45 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -84,11 +84,13 @@
     }
 
     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+        ASSERT_NE(nullptr, mOutBuffer);
         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
         TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
     }
 
     void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+        ASSERT_NE(nullptr, mOutBuffer);
         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
         const bool leftBorder = rect.left > 0;
         const bool topBorder = rect.top > 0;
@@ -146,6 +148,7 @@
     }
 
     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+        ASSERT_NE(nullptr, mOutBuffer);
         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
         const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
@@ -163,10 +166,14 @@
     void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
 
     explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
-        mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
+        if (mOutBuffer) {
+            mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
+        }
     }
 
-    ~ScreenCapture() { mOutBuffer->unlock(); }
+    ~ScreenCapture() {
+        if (mOutBuffer) mOutBuffer->unlock();
+    }
 
 private:
     sp<GraphicBuffer> mOutBuffer;